﻿
#region Usings
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
//using Microsoft.Scripting.Runtime;
#endregion


namespace FasterWPF
{
    /// <summary>
    ///  Type that is passed-along each call in the BeginSettings...EndSettings chain
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class SettingsChain<T> : Tuple<T, List<Func<T, T>>>
    {
        public SettingsChain(T chain, List<Func<T, T>> startlist)
            : base(chain, startlist)
        {}
    }

    //[assembly: Microsoft.Scripting.Runtime.ExtensionType(
    //typeof(Tuple),
    //typeof(FasterWPF.SettingsManager)
    //)]

    //This class contains methods pertaining to Common Settings
    public static class SettingsManager
    {
        #region BeginSettings . . . EndSettings

        /// <summary>
        /// Start of a BeginSettings...EndSettings chain of Set methods. Alternatively, Set methods may be called directly on Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <returns></returns>
        public static SettingsChain<T> BeginSettings<T>(this T chain)
        {
            List<Func<T, T>> startList = new List<Func<T, T>>();
            SettingsChain<T> parm = new SettingsChain<T>(chain, startList);
            return parm;
        }

        /// <summary>
        /// End of a BeginSettings...EndSettings chain of Set methods. If this ending method is NOT called then the Set methods will not be applied.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <returns></returns>
        public static SettingsChain<T> EndSettings<T>(this SettingsChain<T> chain)
            where T : FrameworkElement
        {
            chain.Item1.Apply<T>(t =>
            {
                foreach (Func<T, T> f in chain.Item2)
                {
                    f(t);
                }
            });

            return chain;
        }

        /// <summary>
        /// Store a Property value to be applied by Type to children when BeginComposite...EndComposite chain is called. Property must be valid on K and writeable.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static SettingsChain<T> Set<K, T>(this SettingsChain<T> chain, string propertyOnK, object value)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            chain.Item2.Add(((container) =>
            {
                return container.Set<K, T>(propertyOnK, value);
            }));

            return chain;
        }

        /// <summary>
        /// Store a Property value to be applied to children at X-Y (row, column) when BeginComposite...EndComposite chain is called. Property must be valid on K and writeable.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static SettingsChain<T> Set<K, T>(this SettingsChain<T> chain, int row, int column, string propertyOnK, object value)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            chain.Item2.Add(((container) =>
            {
                return container.Set<K, T>(row, column, propertyOnK, value);
            }));

            return chain;
        }

        /// <summary>
        ///  Store a Property value to be applied to children starting at rowStart and counting for rowCount, at column, when BeginComposite...EndComposite chain is called. Property must be valid on K and writeable.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="column"></param>
        /// <param name="rowStart"></param>
        /// <param name="rowCount"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static SettingsChain<T> SetToCol<K, T>(this SettingsChain<T> chain, int column, int rowStart, int rowCount, string propertyOnK, object value)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetToCol<K, T>(column, rowStart, rowCount, propertyOnK, value);
            }));

            return chain;
        }

        /// <summary>
        ///  Store a Property value to be applied to children starting at colStart and counting for colCount, at row, when BeginComposite...EndComposite chain is called. Property must be valid on K and writeable.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="column"></param>
        /// <param name="rowStart"></param>
        /// <param name="rowCount"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static SettingsChain<T> SetToRow<K, T>(this SettingsChain<T> chain, int row, int colStart, int colCount, string propertyOnK, object value)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetToRow<K, T>(row, colStart, colCount, propertyOnK, value);
            }));

            return chain;
        }

        /// <summary>
        /// Store settings to be applied on Border of children when BeginComposite...EndComposite chain is called.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="brush"></param>
        /// <param name="thickness"></param>
        /// <returns></returns>
        public static SettingsChain<T> SetItemBorderSettings<T>(this SettingsChain<T> chain, double width, double height, Brush brush, Thickness thickness) where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetItemBorderSettings<T>(width, height, brush, thickness);
            }));

            return chain;
        }
        
        /// <summary>
        /// Store several settings to be applied on Border of children when BeginComposite...EndComposite chain is called.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="brush"></param>
        /// <param name="thickness"></param>
        /// <param name="cornerRadius"></param>
        /// <param name="padding"></param>
        /// <returns></returns>
        public static SettingsChain<T> SetItemBorderSettingsFull<T>(this SettingsChain<T> chain, double width, double height, Brush brush, Thickness thickness, CornerRadius cornerRadius, Thickness padding) where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetItemBorderSettingsFull<T>(width, height, brush, thickness, cornerRadius, padding);
            }));

            return chain;
        }

        /// <summary>
        /// Store action to be applied by Type to children when BeginComposite...EndComposite chain is called. The action should update an Attached Property, e.g. obj => { obj.SetValue(Grid.ColumnSpanProperty, 2); }
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static SettingsChain<T> SetAttachedProperty<K, T>(this SettingsChain<T> chain, string propertyOnK, Action<K> value)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetAttachedProperty<K, T>(propertyOnK, value);
            }));

            return chain;
        }

        /// <summary>
        /// Store action to be applied to children at X-Y (row, column) when BeginComposite...EndComposite chain is called. The action should update an Attached Property, e.g. obj => { obj.SetValue(Grid.ColumnSpanProperty, 2); }
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="row"></param>
        /// <param name="col"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static SettingsChain<T> SetAttachedProperty<K, T>(this SettingsChain<T> chain, string propertyOnK, int row, int col, Action<K> value)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetAttachedProperty<K, T>(propertyOnK, row, col, value);
            }));

            return chain;
        }

        #region Label

        public static SettingsChain<T> SetFontOnLabel<T>(this SettingsChain<T> chain, int row, int column, string family, double fontSize, FontWeight weights, FontStyle fontStyle)
     where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetFontOnLabel<T>(row, column, family, fontSize, weights, fontStyle);
            }));

            return chain;
        }

        public static SettingsChain<T> SetZIndex<K, T>(this SettingsChain<T> chain, int row, int column, int zIndex)
            where K: FrameworkElement, new()
            where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetZIndex<K, T>(row, column, zIndex);
            }));

            return chain;
        }

        public static SettingsChain<T> RemoveZIndexSetting<K, T>(this SettingsChain<T> chain, int row, int column)
            where K : FrameworkElement, new()
            where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.RemoveZIndexSetting<K, T>(row, column);
            }));

            return chain;
        }

        public static SettingsChain<T> SetFontToColForLabel<T>(this SettingsChain<T> chain, int column, int rowStart, int rowCount, string family, double fontSize, FontWeight weights, FontStyle fontStyle)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetFontToColForLabel<T>(column, rowStart, rowCount, family, fontSize, weights, fontStyle);
            }));

            return chain;
        }

        public static SettingsChain<T> SetFontToRowForLabel<T>(this SettingsChain<T> chain, int row, int colStart, int colCount, string family, double fontSize, FontWeight weights, FontStyle fontStyle)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetFontToRowForLabel<T>(row, colStart, colCount, family, fontSize, weights, fontStyle);
            }));

            return chain;
        }

        #endregion
        
        #region TextBlock

        public static SettingsChain<T> SetTextColorToRowByStyleKey<T>(this SettingsChain<T> chain, string styleKey, int row, int colStart, int colCount) where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextColorToRowByStyleKey<T>(styleKey, row, colStart, colCount);
            }));

            return chain;
        }

        public static SettingsChain<T> SetFontToRowByStyleKey<T>(this SettingsChain<T> chain, string styleKey, int row, int colStart, int colCount) where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetFontToRowByStyleKey<T>(styleKey, row, colStart, colCount);
            }));

            return chain;
        }

        public static SettingsChain<T> CreateColorStyleKey<T>(this SettingsChain<T> chain, string styleKey, Brush newBrush)
    where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.CreateColorStyleKey<T>(styleKey, newBrush);
            }));

            return chain;
        }

        public static SettingsChain<T> CreateFontStyleKey<T>(this SettingsChain<T> chain, string styleKey, string family, double fontSize, FontWeight weights,
FontStyle fontStyle)
    where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.CreateFontStyleKey<T>(styleKey, family, fontSize, weights, fontStyle);
            }));

             return chain;
        }

        public static SettingsChain<T> SetFontToCol<T>(this SettingsChain<T> chain, int column, int rowStart, int rowCount, string family, double fontSize, FontWeight weights, FontStyle fontStyle)
    where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetFontToCol<T>(column, rowStart, rowCount, family, fontSize, weights, fontStyle);
            }));

            return chain;
        }

        public static SettingsChain<T> SetFontToRow<T>(this SettingsChain<T> chain, int row, int colStart, int colCount, string family, double fontSize, FontWeight weights, FontStyle fontStyle)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetFontToRow<T>(row, colStart, colCount, family, fontSize, weights, fontStyle);
            }));

            return chain;
        }

        public static SettingsChain<T> SetFont<T>(this SettingsChain<T> chain, int row, int column, string family, double fontSize, FontWeight weights, FontStyle fontStyle, TextDecorationCollection textDecorations) 
            where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetFont<T>(row, column, family, fontSize, weights, fontStyle, textDecorations);
            }));

            return chain;
        }
        
        public static SettingsChain<T> SetFont<T>(this SettingsChain<T> chain, int row, int column, string family, double fontSize, FontWeight weights, FontStyle fontStyle)
            where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetFont<T>(row, column, family, fontSize, weights, fontStyle);
            }));

            return chain;
        }

        public static SettingsChain<T> SetTextColor<T>(this SettingsChain<T> chain, int row, int column, Brush brush)
            where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextColor<T>(row, column, brush);
            }));

            return chain;
        }
        
        public static SettingsChain<T> SetTextColorForLabel<T>(this SettingsChain<T> chain, int row, int column, Brush brush)
            where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextColorForLabel<T>(row, column, brush);
            }));

            return chain;
        }

        public static SettingsChain<T> SetTextColor<T>(this SettingsChain<T> chain, int row, int column, byte red, byte green, byte blue, byte alpha)
    where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextColor<T>(row, column, red, green, blue, alpha);
            }));

            return chain;
        }

        public static SettingsChain<T> SetTextColorToCol<T>(this SettingsChain<T> chain, int column, int rowStart, int rowCount, Brush newBrush)
             where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextColorToCol<T>(column, rowStart, rowCount, newBrush);
            }));

            return chain;
        }

        public static SettingsChain<T> SetTextPadding<T>(this SettingsChain<T> chain, int row, int column, Thickness thickness)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextPadding<T>(row, column, thickness);
            }));

            return chain;
        }

        public static SettingsChain<T> SetTextMargin<T>(this SettingsChain<T> chain, int row, int column, Thickness thickness)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextMargin<T>(row, column, thickness);
            }));

            return chain;
        }

        public static SettingsChain<T> SetVerticalAlignment<T>(this SettingsChain<T> chain, int row, int column, System.Windows.VerticalAlignment vertAlign) where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetVerticalAlignment<T>(row, column, vertAlign);
            }));

            return chain;
        }

        public static SettingsChain<T> SetHorizontalAlignmentForText<T>(this SettingsChain<T> chain, int row, int column, TextAlignment horizAlignSetting)
            where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetHorizontalAlignmentForText<T>(row, column, horizAlignSetting);
            }));

            return chain;
        }

        public static SettingsChain<T> SetHorizontalAlignmentForLabel<T>(this SettingsChain<T> chain, int row, int column, HorizontalAlignment horizAlignSetting)
    where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetHorizontalAlignmentForLabel<T>(row, column, horizAlignSetting);
            }));

            return chain;
        }

        public static SettingsChain<T> SetTextWrapping<T>(this SettingsChain<T> chain, int row, int column, System.Windows.TextWrapping textWrap)
             where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextWrapping<T>(row, column, textWrap);
            }));

            return chain;
        }

        public static SettingsChain<T> SetTextBackground<T>(this SettingsChain<T> chain, int row, int column, Brush brush)
             where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextBackground<T>(row, column, brush);
            }));

            return chain;
        }

        public static SettingsChain<T> SetTextVisibility<T>(this SettingsChain<T> chain, int row, int column, Visibility visibility)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextVisibility<T>(row, column, visibility);
            }));
            return chain;
        }

        public static SettingsChain<T> SetTextMaxHeight<T>(this SettingsChain<T> chain, int row, int column, double maxHeight)
             where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextMaxHeight<T>(row, column, maxHeight);
            }));
            return chain;
        }

        public static SettingsChain<T> SetTextMinHeight<T>(this SettingsChain<T> chain, int row, int column, double minHeight)
     where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextMinHeight<T>(row, column, minHeight);
            }));
            return chain;
        }


        public static SettingsChain<T> SetTextMaxWidth<T>(this SettingsChain<T> chain, int row, int column, double maxWidth)
                     where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextMaxWidth<T>(row, column, maxWidth);
            }));
            return chain;
        }

        public static SettingsChain<T> SetTextMinWidth<T>(this SettingsChain<T> chain, int row, int column, double minWidth)
             where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextMinWidth<T>(row, column, minWidth);
            }));
            return chain;
        }

        public static SettingsChain<T> SetTextEffect<T>(this SettingsChain<T> chain, int row, int column, System.Windows.Media.Effects.Effect effect)
     where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetTextEffect<T>(row, column, effect);
            }));

            return chain;
        }

        #endregion

        #region Image

        public static SettingsChain<T> SetImageHorizontalAlignment<T>(this SettingsChain<T> chain, int row, int column, HorizontalAlignment align)
     where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetImageHorizontalAlignment<T>(row, column, align);
            }));

            return chain;
        }

        public static SettingsChain<T> SetImageClip<T>(this SettingsChain<T> chain, int row, int column, Geometry geometryToClipBy)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetImageClip<T>(row, column, geometryToClipBy);
            }));

            return chain;
        }

        public static SettingsChain<T> SetImageStretch<T>(this SettingsChain<T> chain, int row, int column, Stretch stretch)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetImageStretch<T>(row, column, stretch);
            }));

            return chain;
        }

        public static SettingsChain<T> SetImageStretchDirection<T>(this SettingsChain<T> chain, int row, int column, StretchDirection stretchDirection)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetImageStretchDirection<T>(row, column, stretchDirection);
            }));

            return chain;
        }


        public static SettingsChain<T> SetImageMargin<T>(this SettingsChain<T> chain, int row, int column, Thickness thickness)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetImageMargin<T>(row, column, thickness);
            }));

            return chain;
        }


        public static SettingsChain<T> SetImageVisibility<T>(this SettingsChain<T> chain, int row, int column, Visibility visibility)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetImageVisibility<T>(row, column, visibility);
            }));

            return chain;
        }

        #endregion

        #region Other
        public static SettingsChain<T> SetItemBorderColorAndThickness<T>(this SettingsChain<T> chain, byte red, byte green, byte blue, byte alpha, Thickness thickness) where T : FrameworkElement
        {
            Brush brush = BrushExt.CreateSolidColorBrushFromRGB(red, green, blue, alpha);
            (chain.Item1 as FrameworkElement).SetItemBorderColorAndThickness(brush, thickness);
            return chain;
        }

        public static SettingsChain<T> SetItemBorderColorAndThickness<T>(this SettingsChain<T> chain, Brush brush, Thickness thickness) where T : FrameworkElement
        {
            (chain.Item1 as FrameworkElement).SetItemBorderColorAndThickness(brush, thickness);
            return chain;
        }

        public static SettingsChain<T> SetBackgroundColorOnControl<T>(this SettingsChain<T> chain, Brush brush)
where T : Control
        {
            (chain.Item1 as Control).Background = brush;

            return chain;
        }

        public static SettingsChain<T> SetBackgroundColorOnItemsControl<T>(this SettingsChain<T> chain, Brush brush)
where T : ItemsControl
        {
            (chain.Item1 as ItemsControl).Background = brush;

            return chain;
        }
        
        public static SettingsChain<T> SetBackgroundColor<T>(this SettingsChain<T> chain, Brush brush)
where T : Panel
        {
            (chain.Item1 as Panel).Background = brush;

            return chain;
        }

        public static SettingsChain<T> SetUseLayoutRounding<T>(this SettingsChain<T> chain, bool useLayoutRounding)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetUseLayoutRounding<T>(useLayoutRounding);
            }));

            return chain;
        }

        public static SettingsChain<T> SetGroupItemConverter<T>(this SettingsChain<T> chain, Func<Border, string> functionForInItemConverter)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetGroupItemConverter<T>(functionForInItemConverter);
            }));

            return chain;
        }

        public static SettingsChain<T> SetGroupItemFrameworkElementFactory<T>(this SettingsChain<T> chain, FrameworkElementFactory frameworkElementFactory)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetGroupItemFrameworkElementFactory<T>(frameworkElementFactory);
            }));

            return chain;
        }

        public static SettingsChain<T> SetGroupExpanderFrameworkElementFactory<T>(this SettingsChain<T> chain, FrameworkElementFactory frameworkElementFactory)
where T : FrameworkElement
        {
            chain.Item2.Add(((container) =>
            {
                return container.SetGroupExpanderFrameworkElementFactory<T>(frameworkElementFactory);
            }));

            return chain;
        }
        #endregion

        #endregion

        #region Core Methods

        /// <summary>
        /// Get a stored setting by key, e.g. chain.GetSetting("IParent");
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="K"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static K GetSetting<T, K>(this T chain, string key) where T : FrameworkElement
        {
            K setting = default(K);

            setting = (K)((Dictionary<string, object>)(chain.Tag))[key];

            return setting;
        }

        /// <summary>
        ///  Store a Property value to be applied by Type to children when BeginComposite...EndComposite chain is called. Property must be valid on K and writeable.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T Set<K, T>(this T chain, string propertyOnK, object value) 
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            K k1 = new K();
            string fullKey = k1.GetType().Name.ToString() + propertyOnK;

            PropertyInfo pi = null;
            pi = k1.GetType().GetProperty(propertyOnK);
            if (pi == null || !pi.CanWrite)
            {
                throw new InvalidPropertyException("Property must be valid on K and writeable.", propertyOnK);
            }
            
            return chain.StoreSetting<T>(fullKey, value);
        }
        
        /// <summary>
        ///  Store action to be applied by Type to children when BeginComposite...EndComposite chain is called. The action should update an Attached Property, e.g. obj => { obj.SetValue(Grid.ColumnSpanProperty, 2); }
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T SetAttachedProperty<K, T>(this T chain, string propertyOnK, Action<K> value)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            K k1 = new K();
            string fullKey = k1.GetType().Name.ToString() + propertyOnK;
            Dictionary<string, object> attachDict = chain.GetAttachedPropertiesDictionary();

            //ADD_TO_DICTIONARY BOOKMARK - 6. Attached Properties
            attachDict.Add(fullKey, value);

            return chain;
        }

        /// <summary>
        ///  Store action to be applied to children at X-Y (row, column) when BeginComposite...EndComposite chain is called. The action should update an Attached Property, e.g. obj => { obj.SetValue(Grid.ColumnSpanProperty, 2); }
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="row"></param>
        /// <param name="col"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T SetAttachedProperty<K, T>(this T chain, string propertyOnK, int row, int col, Action<K> value)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            K k1 = new K();
            string row_col = row + "_" + col;
            string fullKey = k1.GetType().Name.ToString() + propertyOnK + "_" + row_col;
            Dictionary<string, object> attachDict = chain.GetAttachedPropertiesByRowColDictionary();

            //ADD_TO_DICTIONARY BOOKMARK - 7. Attached Properties By Row Column
            attachDict.Add(fullKey, value);

            return chain;
        }

        /// <summary>
        ///  Store a Property value to be applied to children at X-Y (row, column) when BeginComposite...EndComposite chain is called. Property must be valid on K and writeable.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T Set<K, T>(this T chain, int row, int column, string propertyOnK, object value) 
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            K k1 = new K();
            string fullKey = k1.GetType().Name.ToString() + propertyOnK;

            PropertyInfo pi = null;
            pi = k1.GetType().GetProperty(propertyOnK);
            if (pi == null || !pi.CanWrite)
            {  
                throw new InvalidPropertyException("Property must be valid on K and writeable.", propertyOnK);
            }
    
            return chain.StoreSetting<T>(fullKey + "_" + row + "_" + column, value);
        }


        /// <summary>
        ///  Change a previously stored Setting, a Property value to be applied to children at X-Y (row, column) when BeginComposite...EndComposite chain is called. Property must be valid on K and writeable.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T ChangeSetting<K, T>(this T chain, int row, int column, string propertyOnK, object value)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            K k1 = new K();
            string fullKey = k1.GetType().Name.ToString() + propertyOnK;

            PropertyInfo pi = null;
            pi = k1.GetType().GetProperty(propertyOnK);
            if (pi == null || !pi.CanWrite)
            {
                throw new InvalidPropertyException("Property must be valid on K and writeable.", propertyOnK);
            }

            return chain.ChangeSettingInternally<T>(fullKey + "_" + row + "_" + column, value);
        }

        private static T ChangeSettingInternally<T>(this T chain, string fullKey, object value)
            where T : FrameworkElement
        {
            chain.GetSettingsDictionary().Remove(fullKey);
            chain.GetSettingsDictionary().Add(fullKey, value);
            return chain;
        }

        /// <summary>
        ///  Add a stored Setting outside of BeginSettings . . . EndSettings, a Property value to be applied to children at X-Y (row, column) when BeginComposite...EndComposite chain is called. Property must be valid on K and writeable.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T AddSetting<K, T>(this T chain, int row, int column, string propertyOnK, object value)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            K k1 = new K();
            string fullKey = k1.GetType().Name.ToString() + propertyOnK;

            PropertyInfo pi = null;
            pi = k1.GetType().GetProperty(propertyOnK);
            if (pi == null || !pi.CanWrite)
            {
                throw new InvalidPropertyException("Property must be valid on K and writeable.", propertyOnK);
            }

            return chain.AddSettingInternally<T>(fullKey + "_" + row + "_" + column, value);
        }

        private static T AddSettingInternally<T>(this T chain, string fullKey, object value)
    where T : FrameworkElement
        {
            chain.GetSettingsDictionary().Add(fullKey, value);
            return chain;
        }

        public static void RemoveSetting<T>(this T chain, string key)
             where T : FrameworkElement
        {            
            Dictionary<string, object> settings = (Dictionary<string, object>)chain.Tag;
        
           if (settings.Keys.Contains(key))
           {
                //REMOVE_FROM_DICTIONARY BOOKMARK - 1. Settings
                settings.Remove(key);
           } 
       }

       public static void RemoveAttachedPropertySetting<K, T>(this T chain, string propertyOnK)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            K k1 = new K();
            string fullKey = k1.GetType().Name.ToString() + propertyOnK;
            Dictionary<string, object> attachDict = chain.GetAttachedPropertiesDictionary();

            if (attachDict.Keys.Contains(fullKey))
            {
                //REMOVE_FROM_DICTIONARY BOOKMARK - 6. Attached Properties
                attachDict.Remove(fullKey);
            }
        }

       public static void RemoveAttachedPropertySetting<K, T>(this T chain, string propertyOnK, int row, int col)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            K k1 = new K();
            string row_col = row + "_" + col;
            string fullKey = k1.GetType().Name.ToString() + propertyOnK + "_" + row_col;
            Dictionary<string, object> attachDict = chain.GetAttachedPropertiesByRowColDictionary();

            if (attachDict.Keys.Contains(fullKey))
            {
                //REMOVE_FROM_DICTIONARY BOOKMARK - 7. Attached Properties By Row Column
                attachDict.Remove(fullKey);
            }
        }

        /// <summary>
        /// Store a Property value to be applied to children starting at rowStart and counting for rowCount, at column, when BeginComposite...EndComposite chain is called. Property must be valid on K and writeable.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="column"></param>
        /// <param name="rowStart"></param>
        /// <param name="rowCount"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T SetToCol<K, T>(this T chain, int column, int rowStart, int rowCount, string propertyOnK, object value)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            K k1 = new K();
            string fullKey = k1.GetType().Name.ToString() + propertyOnK;

            PropertyInfo pi = null;
            pi = k1.GetType().GetProperty(propertyOnK);
            if (pi == null || !pi.CanWrite)
            {   
                throw new InvalidPropertyException("Property must be valid on K and writeable.", propertyOnK);
            }
            
            Enumerable.Range(rowStart, rowCount).ToList().ForEach(innerInt =>
            {
                chain.StoreSetting<T>(fullKey + "_" + innerInt + "_" + column, value);
            });

            return chain;
        }

        /// <summary>
        /// Store a Property value to be applied to children starting at colStart and counting for colCount, at row, when BeginComposite...EndComposite chain is called. Property must be valid on K and writeable.
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="colStart"></param>
        /// <param name="colCount"></param>
        /// <param name="propertyOnK"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T SetToRow<K, T>(this T chain, int row, int colStart, int colCount, string propertyOnK, object value)
            where T : FrameworkElement
            where K : FrameworkElement, new()
        {
            K k1 = new K();
            string fullKey = k1.GetType().Name.ToString() + propertyOnK;

            PropertyInfo pi = null;
            pi = k1.GetType().GetProperty(propertyOnK);
            if (pi == null || !pi.CanWrite)
            {
                throw new InvalidPropertyException("Property must be valid on K and writeable.", propertyOnK);
            }

            Enumerable.Range(colStart, colCount).ToList().ForEach(innerInt =>
            {
                chain.StoreSetting<T>(fullKey + "_" + row + "_" + innerInt, value);
            });

            return chain;
        }

        /// <summary>
        /// Store a setting by key and value. Used internally by WPF Composites. Key should be unique and descriptive, e.g. source.StoreSetting("IParent", borderParent);
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T StoreSetting<T>(this T chain, string key, object value) where T : FrameworkElement
        {
            Dictionary<string, object> settings = new Dictionary<string, object>();

            if (chain.Tag == null)  //if Settings Dictionary hasn't already been added, add it here
            {
                //you can FIND each spot in code where items are added to these dictionaries
                //by doing a FIND on the string "ADD_TO_DICTIONARY BOOKMARK"
                settings.Add("ChildLookup", new Dictionary<string, object>());
                settings.Add("CompositeLookup", new Dictionary<string, object>());
                settings.Add("DisposablesDictionary", new Dictionary<string, IDisposable>());
                settings.Add("AttachedPropertiesDict", new Dictionary<string, object>());
                settings.Add("AttachedPropertiesByRowColDict", new Dictionary<string, object>());
                settings.Add("KeyList", new List<String>());

                chain.Tag = settings; //Store the settings dictionary on the ListBox's tag
            }
            else
            {
                settings = (Dictionary<string, object>)chain.Tag;
            }

            if (!settings.Keys.Contains(key))
            {
                //ADD_TO_DICTIONARY BOOKMARK - 1. Settings
                settings.Add(key, value);
            }
            else
            {
                if (!key.Contains("DataGridPersistArgs")) //allow dupes only for DataGridPersistArgs
                {
                    throw new DuplicateSettingException("Duplicate setting detected! A setting may only be set once. KEY: " + key, key);
                }
            }

            chain.Tag = settings;

            return chain;
        }

        /// <summary>
        /// Checks whether a specific setting has already been stored in the Settings Dictionary
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool ContainsSetting<T>(this T chain, string key) where T : FrameworkElement
        {
            bool retVal = false;

            if (((Dictionary<string, object>)(chain.Tag)).Keys.Contains(key))
            {
                retVal = true;
            }

            return retVal;
        }

        /// <summary>
        /// Checks whether a Font setting has already been stored in the Settings Dictionary at a particular row-column (X-Y coordinate)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool ContainsFontSettingAtXY<T>(this T chain, int row, int column) where T : FrameworkElement
        {
            bool retVal = false;

            if (((Dictionary<string, object>)(chain.Tag)).Keys.Contains("TextBlock" + "FontFamily" + "_" + row + "_" + column))
            {
                retVal = true;
            }

            return retVal;
        }

        /// <summary>
        /// Gets the Settings Dictionary that is stored on the Tag of the Parent.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static Dictionary<string, object> GetSettingsDictionary<T>(this T source) where T : FrameworkElement
        {
            Dictionary<string, object> settings = ((Dictionary<string, object>)source.Tag);

            return settings;
        }

        #endregion

        #region Get Setting Methods

        #region Get or Default

        public static Brush GetForegroundSettingOrDefault(Dictionary<string, object> settings, string foregroundSetting)
        {
            Brush b = null;

            if (settings.Keys.Contains(foregroundSetting))
            {
                b = settings[foregroundSetting].Cast<Brush>();
            }
            else
            {
                b = new SolidColorBrush(Colors.Black); // set default Brush
            }

            return b;
        }

        public static FontSettings GetFontSettingOrDefault(Dictionary<string, object> settings, string fontSetting)
        {
            FontSettings storedFont = null;
            if (settings.Keys.Contains(fontSetting))
            {
                storedFont = settings[fontSetting].Cast<FontSettings>();
            }
            else
            {
                storedFont = FontExt.CreateFont("Segoe UI", 11D, FontWeights.Normal, FontStyles.Normal); //create default Font
            }
            return storedFont;
        }

        #endregion
        
        public static ContainerType GetContainerType<T>(this T chain) where T : FrameworkElement
        {
            return GetSetting<T, ContainerType>(chain, "ContainerTypeEnum");
        }

        public static IComposite GetIComposite<T>(this T chain)
            where T : FrameworkElement
        {
            return GetSetting<T, IComposite>(chain, "IComposite");
        }
        #endregion

        #region Store Setting Methods

        public static T SetUseLayoutRounding<T>(this T chain, bool useLayoutRounding)
    where T : FrameworkElement
        {
            chain.StoreSetting<T>("UseLayoutRounding", useLayoutRounding);
            return chain;
        }

        public static T SetGroupItemConverter<T>(this T chain, Func<Border, string> functionForInItemConverter)
where T : FrameworkElement
        {
            chain.StoreSetting<T>("GroupItemConverter", functionForInItemConverter);
            return chain;
        }

        public static T SetGroupItemFrameworkElementFactory<T>(this T chain, FrameworkElementFactory frameworkElementFactory)
where T : FrameworkElement
        {
            chain.StoreSetting<T>("GroupItemFrameworkElementFactory", frameworkElementFactory);
            return chain;
        }

        public static T SetGroupExpanderFrameworkElementFactory<T>(this T chain, FrameworkElementFactory frameworkElementFactory)
where T : FrameworkElement
        {
            chain.StoreSetting<T>("GroupExpanderFrameworkElementFactory", frameworkElementFactory);
            return chain;
        }

        #region Border, Row, and Container Type Settings

        public static T SetItemBorderColorAndThickness<T>(this T chain, byte red, byte green, byte blue, byte alpha, Thickness thickness) where T : FrameworkElement
        {
            Brush brush = BrushExt.CreateSolidColorBrushFromRGB(red, green, blue, alpha);
            return chain.SetItemBorderColorAndThickness(brush, thickness);
        }    

        public static T SetItemBorderColorAndThickness<T>(this T chain, Brush brush, Thickness thickness) where T : FrameworkElement
        {
            chain.GetSettingsDictionary()["BorderSettings"] = new BorderSettings() { Width = double.NaN, Height = double.NaN, BorderBrush = brush, BorderThickness = thickness, CornerRadius = new CornerRadius(0), Padding = new Thickness(0) };
            return chain;
        }

        public static T SetItemBorderSettings<T>(this T chain, double width, double height, Brush brush, Thickness thickness) where T : FrameworkElement
        {
            chain.GetSettingsDictionary()["BorderSettings"] = new BorderSettings() { Width = width, Height = height, BorderBrush = brush, BorderThickness = thickness, CornerRadius = new CornerRadius(0), Padding = new Thickness(0) };
            return chain;
        }

        public static T SetItemBorderSettingsFull<T>(this T chain, double width, double height, Brush brush, Thickness thickness, CornerRadius cornerRadius, Thickness padding) where T : FrameworkElement
        {
            chain.GetSettingsDictionary()["BorderSettings"] = new BorderSettings() { Width = width, Height = height, BorderBrush = brush, BorderThickness = thickness, CornerRadius = cornerRadius, Padding = padding };
            return chain;
        }

        public static T AddItemBorder<T>(this T chain, double width, double height, Brush brush, Thickness thickness, CornerRadius cornerRadius, Thickness padding) where T : FrameworkElement
        {
            chain.StoreSetting<T>("Border", CommonExt.CreateBorder(chain, width, height, brush, thickness, Visibility.Visible, cornerRadius, padding));
            return chain;
        }

        public static T AddItemBorder<T>(this T chain, double width, double height, Brush brush, Thickness thickness) where T : FrameworkElement
        {
            chain.StoreSetting<T>("Border", CommonExt.CreateBorder(chain, width, height, brush, thickness, Visibility.Visible, new CornerRadius(0), new Thickness(0)));
            return chain;
        }

        public static T AddItemBorder<T>(this T chain, Brush brush, Thickness thickness) where T : FrameworkElement
        {
            chain.StoreSetting<T>("Border", CommonExt.CreateBorder(chain, double.NaN, double.NaN, brush, thickness, Visibility.Visible, new CornerRadius(0), new Thickness(0)));
            return chain;
        }

        public static T SetIComposite<T>(this T chain, IComposite icomposite) 
            where T : FrameworkElement
        {
            StoreSetting<T>(chain, "IComposite", icomposite);
            return chain;
        }

        public static T SetContainerType<T>(this T chain, ContainerType ContainerType) where T : FrameworkElement
        {
            StoreSetting<T>(chain, "ContainerTypeEnum", ContainerType);
            return chain;
        }

        public static T SetRowPadding<T>(this T chain, Thickness padding)
    where T : FrameworkElement
        {
            chain.StoreSetting<T>("Padding", padding);
            return chain;
        }

        #endregion

        #region Grid Settings

        public static GridSettings CompositeGridDimensions<T>(this T chain, int NumRows, int NumColumns, double colWidthToRepeat, GridUnitType unitTypeToRepeat)
where T : FrameworkElement
        {
            return chain.CompositeGridDimensions(double.NaN, double.NaN, NumRows, NumColumns, colWidthToRepeat, unitTypeToRepeat);
        }

        public static GridSettings CompositeGridDimensions<T>(this T chain, double width, double height, int NumRows, int NumColumns, double colWidthToRepeat, GridUnitType unitTypeToRepeat)
     where T : FrameworkElement
        {
            List<double> colWidths = new List<double>();
            List<GridUnitType> colUnitTypes = new List<GridUnitType>();

            Enumerable.Range(1, NumColumns).ToList().ForEach(i =>
            {
                colWidths.Add(colWidthToRepeat);
                colUnitTypes.Add(unitTypeToRepeat);
            });

            GridSettings gs = new GridSettings()
            {
                NumColumns = NumColumns,
                NumRows = NumRows,
                ColWidths = colWidths,
                ColUnitTypes = colUnitTypes,
                Height = height,
                Width = width
            };

            return gs;
        }

        public static T SetCompositeGridDimensions<T>(this T chain, double width, double height, int NumRows, int NumColumns, double colWidthToRepeat, GridUnitType unitTypeToRepeat)
             where T : FrameworkElement
        {
            List<double> colWidths = new List<double>();
            List<GridUnitType> colUnitTypes = new List<GridUnitType>();

            Enumerable.Range(1, NumColumns).ToList().ForEach(i =>
            {
                colWidths.Add(colWidthToRepeat);
                colUnitTypes.Add(unitTypeToRepeat);
            });

            GridSettings gs = new GridSettings()
            {
                NumColumns = NumColumns,
                NumRows = NumRows,
                ColWidths = colWidths,
                ColUnitTypes = colUnitTypes,
                Height = height,
                Width = width
            };
            chain.StoreSetting("GridSettings", gs);

            return chain;
        }
        
        public static T SetCompositeGridDimensions<T>(this T chain, int NumRows, int NumColumns, double colWidthToRepeat, GridUnitType unitTypeToRepeat)
             where T : FrameworkElement
        {
            chain.SetCompositeGridDimensions(double.NaN, double.NaN, NumRows, NumColumns, colWidthToRepeat, unitTypeToRepeat);

            return chain;
        }

        //This method is for Iron Python. 
        //It uses type inference and may get confused by too many similar overloaded generic methods
//        public static GridSettings CompositeGridDimensionsP<T>(this T chain, int NumRows, int NumColumns, double colWidthToRepeat, GridUnitType unitTypeToRepeat, double rowHeightToRepeat, GridUnitType rowUnitTypeToRepeat)
//where T : FrameworkElement
//        {
//            return chain.CompositeGridDimensions<T>(double.NaN, double.NaN, NumRows, NumColumns, colWidthToRepeat, unitTypeToRepeat, rowHeightToRepeat, rowUnitTypeToRepeat);
//        }

        public static GridSettings CompositeGridDimensions<T>(this T chain, int NumRows, int NumColumns, double colWidthToRepeat, GridUnitType unitTypeToRepeat, double rowHeightToRepeat, GridUnitType rowUnitTypeToRepeat)
    where T : FrameworkElement
        {
            return chain.CompositeGridDimensions<T>(double.NaN, double.NaN, NumRows, NumColumns, colWidthToRepeat, unitTypeToRepeat, rowHeightToRepeat, rowUnitTypeToRepeat);
        }

    //    public static T SetCompositeGridDimensionsP<T>(this T chain, int NumRows, int NumColumns, double colWidthToRepeat, GridUnitType unitTypeToRepeat, double rowHeightToRepeat, GridUnitType rowUnitTypeToRepeat)
    //where T : FrameworkElement
    //    {
    //        chain.SetCompositeGridDimensions<T>(double.NaN, double.NaN, NumRows, NumColumns, colWidthToRepeat, unitTypeToRepeat, rowHeightToRepeat, rowUnitTypeToRepeat);

    //        return chain;
    //    }

        public static T SetCompositeGridDimensions<T>(this T chain, int NumRows, int NumColumns, double colWidthToRepeat, GridUnitType unitTypeToRepeat, double rowHeightToRepeat, GridUnitType rowUnitTypeToRepeat)
            where T : FrameworkElement
        {
            chain.SetCompositeGridDimensions<T>(double.NaN, double.NaN, NumRows, NumColumns, colWidthToRepeat, unitTypeToRepeat, rowHeightToRepeat, rowUnitTypeToRepeat);

            return chain;
        }

        public static GridSettings CompositeGridDimensions<T>(this T chain, int NumRows, int NumColumns, double colWidth1, GridUnitType unitType1,
double colWidth2 = 9999999999D, GridUnitType unitType2 = GridUnitType.Auto,
double colWidth3 = 9999999999D, GridUnitType unitType3 = GridUnitType.Auto,
double colWidth4 = 9999999999D, GridUnitType unitType4 = GridUnitType.Auto,
double colWidth5 = 9999999999D, GridUnitType unitType5 = GridUnitType.Auto,
double colWidth6 = 9999999999D, GridUnitType unitType6 = GridUnitType.Auto,
double colWidth7 = 9999999999D, GridUnitType unitType7 = GridUnitType.Auto,
double colWidth8 = 9999999999D, GridUnitType unitType8 = GridUnitType.Auto,
double colWidth9 = 9999999999D, GridUnitType unitType9 = GridUnitType.Auto,
double colWidth10 = 9999999999D, GridUnitType unitType10 = GridUnitType.Auto,
double colWidth11 = 9999999999D, GridUnitType unitType11 = GridUnitType.Auto,
double colWidth12 = 9999999999D, GridUnitType unitType12 = GridUnitType.Auto,
double colWidth13 = 9999999999D, GridUnitType unitType13 = GridUnitType.Auto,
double colWidth14 = 9999999999D, GridUnitType unitType14 = GridUnitType.Auto,
double colWidth15 = 9999999999D, GridUnitType unitType15 = GridUnitType.Auto,
double colWidth16 = 9999999999D, GridUnitType unitType16 = GridUnitType.Auto,
double colWidth17 = 9999999999D, GridUnitType unitType17 = GridUnitType.Auto,
double colWidth18 = 9999999999D, GridUnitType unitType18 = GridUnitType.Auto,
double colWidth19 = 9999999999D, GridUnitType unitType19 = GridUnitType.Auto,
double colWidth20 = 9999999999D, GridUnitType unitType20 = GridUnitType.Auto,
double colWidth21 = 9999999999D, GridUnitType unitType21 = GridUnitType.Auto,
double colWidth22 = 9999999999D, GridUnitType unitType22 = GridUnitType.Auto,
double colWidth23 = 9999999999D, GridUnitType unitType23 = GridUnitType.Auto,
double colWidth24 = 9999999999D, GridUnitType unitType24 = GridUnitType.Auto,
double colWidth25 = 9999999999D, GridUnitType unitType25 = GridUnitType.Auto)
where T : FrameworkElement
        {
           return chain.CompositeGridDimensions<T>(double.NaN, double.NaN, NumRows, NumColumns, colWidth1, unitType1,
           colWidth2, unitType2,
           colWidth3, unitType3,
           colWidth4, unitType4,
           colWidth5, unitType5,
           colWidth6, unitType6,
           colWidth7, unitType7,
           colWidth8, unitType8,
           colWidth9, unitType9,
           colWidth10, unitType10,
           colWidth11, unitType11,
           colWidth12, unitType12,
           colWidth13, unitType13,
           colWidth14, unitType14,
           colWidth15, unitType15,
           colWidth16, unitType16,
           colWidth17, unitType17,
           colWidth18, unitType18,
           colWidth19, unitType19,
           colWidth20, unitType20,
           colWidth21, unitType21,
           colWidth22, unitType22,
           colWidth23, unitType23,
           colWidth24, unitType24,
           colWidth25, unitType25);
       }

        public static T SetCompositeGridDimensionsWithRowHt<T>(this T chain, int NumRows, int NumColumns, double rowHeightToRepeat, GridUnitType rowUnitTypeToRepeat, double colWidth1, GridUnitType unitType1,
    double colWidth2 = 9999999999D, GridUnitType unitType2 = GridUnitType.Auto,
    double colWidth3 = 9999999999D, GridUnitType unitType3 = GridUnitType.Auto,
    double colWidth4 = 9999999999D, GridUnitType unitType4 = GridUnitType.Auto,
    double colWidth5 = 9999999999D, GridUnitType unitType5 = GridUnitType.Auto,
    double colWidth6 = 9999999999D, GridUnitType unitType6 = GridUnitType.Auto,
    double colWidth7 = 9999999999D, GridUnitType unitType7 = GridUnitType.Auto,
    double colWidth8 = 9999999999D, GridUnitType unitType8 = GridUnitType.Auto,
    double colWidth9 = 9999999999D, GridUnitType unitType9 = GridUnitType.Auto,
    double colWidth10 = 9999999999D, GridUnitType unitType10 = GridUnitType.Auto,
    double colWidth11 = 9999999999D, GridUnitType unitType11 = GridUnitType.Auto,
    double colWidth12 = 9999999999D, GridUnitType unitType12 = GridUnitType.Auto,
    double colWidth13 = 9999999999D, GridUnitType unitType13 = GridUnitType.Auto,
    double colWidth14 = 9999999999D, GridUnitType unitType14 = GridUnitType.Auto,
    double colWidth15 = 9999999999D, GridUnitType unitType15 = GridUnitType.Auto,
    double colWidth16 = 9999999999D, GridUnitType unitType16 = GridUnitType.Auto,
    double colWidth17 = 9999999999D, GridUnitType unitType17 = GridUnitType.Auto,
    double colWidth18 = 9999999999D, GridUnitType unitType18 = GridUnitType.Auto,
    double colWidth19 = 9999999999D, GridUnitType unitType19 = GridUnitType.Auto,
    double colWidth20 = 9999999999D, GridUnitType unitType20 = GridUnitType.Auto,
    double colWidth21 = 9999999999D, GridUnitType unitType21 = GridUnitType.Auto,
    double colWidth22 = 9999999999D, GridUnitType unitType22 = GridUnitType.Auto,
    double colWidth23 = 9999999999D, GridUnitType unitType23 = GridUnitType.Auto,
    double colWidth24 = 9999999999D, GridUnitType unitType24 = GridUnitType.Auto,
    double colWidth25 = 9999999999D, GridUnitType unitType25 = GridUnitType.Auto)
     where T : FrameworkElement
        {
            chain.SetCompositeGridDimensionsWithRowHt<T>(double.NaN, double.NaN, NumRows, NumColumns, rowHeightToRepeat, rowUnitTypeToRepeat, colWidth1, unitType1,
           colWidth2, unitType2,
           colWidth3, unitType3,
           colWidth4, unitType4,
           colWidth5, unitType5,
           colWidth6, unitType6,
           colWidth7, unitType7,
           colWidth8, unitType8,
           colWidth9, unitType9,
           colWidth10, unitType10,
           colWidth11, unitType11,
           colWidth12, unitType12,
           colWidth13, unitType13,
           colWidth14, unitType14,
           colWidth15, unitType15,
           colWidth16, unitType16,
           colWidth17, unitType17,
           colWidth18, unitType18,
           colWidth19, unitType19,
           colWidth20, unitType20,
           colWidth21, unitType21,
           colWidth22, unitType22,
           colWidth23, unitType23,
           colWidth24, unitType24,
           colWidth25, unitType25);

            return chain;
        }

        public static T SetCompositeGridDimensions<T>(this T chain, int NumRows, int NumColumns, double colWidth1, GridUnitType unitType1,
    double colWidth2 = 9999999999D, GridUnitType unitType2 = GridUnitType.Auto,
    double colWidth3 = 9999999999D, GridUnitType unitType3 = GridUnitType.Auto,
    double colWidth4 = 9999999999D, GridUnitType unitType4 = GridUnitType.Auto,
    double colWidth5 = 9999999999D, GridUnitType unitType5 = GridUnitType.Auto,
    double colWidth6 = 9999999999D, GridUnitType unitType6 = GridUnitType.Auto,
    double colWidth7 = 9999999999D, GridUnitType unitType7 = GridUnitType.Auto,
    double colWidth8 = 9999999999D, GridUnitType unitType8 = GridUnitType.Auto,
    double colWidth9 = 9999999999D, GridUnitType unitType9 = GridUnitType.Auto,
    double colWidth10 = 9999999999D, GridUnitType unitType10 = GridUnitType.Auto,
    double colWidth11 = 9999999999D, GridUnitType unitType11 = GridUnitType.Auto,
    double colWidth12 = 9999999999D, GridUnitType unitType12 = GridUnitType.Auto,
    double colWidth13 = 9999999999D, GridUnitType unitType13 = GridUnitType.Auto,
    double colWidth14 = 9999999999D, GridUnitType unitType14 = GridUnitType.Auto,
    double colWidth15 = 9999999999D, GridUnitType unitType15 = GridUnitType.Auto,
    double colWidth16 = 9999999999D, GridUnitType unitType16 = GridUnitType.Auto,
    double colWidth17 = 9999999999D, GridUnitType unitType17 = GridUnitType.Auto,
    double colWidth18 = 9999999999D, GridUnitType unitType18 = GridUnitType.Auto,
    double colWidth19 = 9999999999D, GridUnitType unitType19 = GridUnitType.Auto,
    double colWidth20 = 9999999999D, GridUnitType unitType20 = GridUnitType.Auto,
    double colWidth21 = 9999999999D, GridUnitType unitType21 = GridUnitType.Auto,
    double colWidth22 = 9999999999D, GridUnitType unitType22 = GridUnitType.Auto,
    double colWidth23 = 9999999999D, GridUnitType unitType23 = GridUnitType.Auto,
    double colWidth24 = 9999999999D, GridUnitType unitType24 = GridUnitType.Auto,
    double colWidth25 = 9999999999D, GridUnitType unitType25 = GridUnitType.Auto)
     where T : FrameworkElement
        {
            chain.SetCompositeGridDimensions<T>(double.NaN, double.NaN, NumRows, NumColumns, colWidth1, unitType1,
           colWidth2, unitType2,
           colWidth3, unitType3,
           colWidth4, unitType4,
           colWidth5, unitType5,
           colWidth6, unitType6,
           colWidth7, unitType7,
           colWidth8, unitType8,
           colWidth9, unitType9,
           colWidth10, unitType10,
           colWidth11, unitType11,
           colWidth12, unitType12,
           colWidth13, unitType13,
           colWidth14, unitType14,
           colWidth15, unitType15,
           colWidth16, unitType16,
           colWidth17, unitType17,
           colWidth18, unitType18,
           colWidth19, unitType19,
           colWidth20, unitType20,
           colWidth21, unitType21,
           colWidth22, unitType22,
           colWidth23, unitType23,
           colWidth24, unitType24,
           colWidth25, unitType25);

            return chain;
        }

        public static CanvasSettings CompositeCanvasSettings<T>(this T chain, double width, double height, Brush backgroundColor, Brush mouseOverColor)
where T : FrameworkElement
        {
            CanvasSettings ws = new CanvasSettings()
            {
                Width = width,
                Height = height,
                BackgroundColor = backgroundColor,
                MouseOverColor = mouseOverColor
            };

            return ws;
        }

        public static T SetCompositeCanvasSettings<T>(this T chain, double width, double height, Brush backgroundColor, Brush mouseOverColor)
where T : FrameworkElement
        {
            CanvasSettings ws = new CanvasSettings()
            {
                Width = width,
                Height = height,
                BackgroundColor = backgroundColor,
                MouseOverColor = mouseOverColor
            };
            chain.StoreSetting<T>("CanvasSettings", ws);
            return chain;
        }

        public static UniformGridSettings CompositeUniformGridSettings<T>(this T chain, int numRows, int numCols, double width, double height)
where T : FrameworkElement
        {
            UniformGridSettings ws = new UniformGridSettings()
            {
                NumRows = numRows,
                NumColumns = numCols,
                Width = width,
                Height = height
            };

            return ws;
        }

        public static T SetCompositeUniformGridSettings<T>(this T chain, int numRows, int numCols, double width, double height)
where T : FrameworkElement
        {
            UniformGridSettings ws = new UniformGridSettings()
            {
                NumRows = numRows,
                NumColumns = numCols,
                Width = width,
                Height = height
            };
            chain.StoreSetting<T>("UniformGridSettings", ws);
            return chain;
        }

        public static DockPanelSettings CompositeDockPanelLastChildFill<T>(this T chain, bool lastChildFill)
where T : FrameworkElement
        {
            DockPanelSettings ws = new DockPanelSettings()
            {
                LastChildFill = lastChildFill
            };

            return ws;
        }

        public static T SetCompositeDockPanelLastChildFill<T>(this T chain, bool lastChildFill)
where T : FrameworkElement
        {
            DockPanelSettings ws = new DockPanelSettings()
            {
                LastChildFill = lastChildFill
            };
            chain.StoreSetting<T>("DockPanelSettings", ws);
            return chain;
        }

        public static WrapPanelSettings CompositeWrapPanelSettings<T>(this T chain, double itemWidth, double itemHeight, Orientation wrapOrientation)
where T : FrameworkElement
        {            
            WrapPanelSettings ws = new WrapPanelSettings(){   
                     ItemWidth = itemWidth,
                     ItemHeight = itemHeight,
                     Orientation = wrapOrientation
            };

            return ws;
        }

        public static T SetCompositeWrapPanelSettings<T>(this T chain, double itemWidth, double itemHeight, Orientation wrapOrientation)
where T : FrameworkElement
        {
            WrapPanelSettings ws = new WrapPanelSettings()
            {
                ItemWidth = itemWidth,
                ItemHeight = itemHeight,
                Orientation = wrapOrientation
            };
            chain.StoreSetting<T>("WrapPanelSettings", ws);
            return chain;
        }


        public static HorizontalPanelSettings CompositeHorizontalPanelSettings<T>(this T chain, double height)
where T : FrameworkElement
        {
            HorizontalPanelSettings ws = new HorizontalPanelSettings()
            {
                Height = height
            };

            return ws;
        }

        public static T SetCompositeHorizontalPanelSettings<T>(this T chain, double height)
where T : FrameworkElement
        {
            HorizontalPanelSettings ws = new HorizontalPanelSettings()
            {
                 Height = height
            };
            chain.StoreSetting<T>("HorizontalPanelSettings", ws);
            return chain;
        }

        public static GridSettings CompositeGridDimensions<T>(this T chain, double width, double height, int NumRows, int NumColumns, double colWidthToRepeat, GridUnitType unitTypeToRepeat, double rowHeightToRepeat, GridUnitType rowUnitTypeToRepeat)
where T : FrameworkElement
        {
            List<double> colWidths = new List<double>();
            List<GridUnitType> colUnitTypes = new List<GridUnitType>();

            Enumerable.Range(1, NumColumns).ToList().ForEach(i =>
            {
                colWidths.Add(colWidthToRepeat);
                colUnitTypes.Add(unitTypeToRepeat);
            });

            List<double> rowHeights = new List<double>();
            List<GridUnitType> rowUnitTypes = new List<GridUnitType>();

            Enumerable.Range(1, NumRows).ToList().ForEach(i =>
            {
                rowHeights.Add(rowHeightToRepeat);
                rowUnitTypes.Add(rowUnitTypeToRepeat);
            });

            GridSettings gs = new GridSettings()
            {
                NumColumns = NumColumns,
                NumRows = NumRows,
                ColWidths = colWidths,
                ColUnitTypes = colUnitTypes,
                RowHeights = rowHeights,
                RowUnitTypes = rowUnitTypes,
                Height = height,
                Width = width
            };
           
            return gs;
        }

        public static T SetCompositeGridDimensions<T>(this T chain, double width, double height, int NumRows, int NumColumns, double colWidthToRepeat, GridUnitType unitTypeToRepeat, double rowHeightToRepeat, GridUnitType rowUnitTypeToRepeat)
     where T : FrameworkElement
        {
            List<double> colWidths = new List<double>();
            List<GridUnitType> colUnitTypes = new List<GridUnitType>();

            Enumerable.Range(1, NumColumns).ToList().ForEach(i =>
            {
                colWidths.Add(colWidthToRepeat);
                colUnitTypes.Add(unitTypeToRepeat);
            });

            List<double> rowHeights = new List<double>();
            List<GridUnitType> rowUnitTypes = new List<GridUnitType>();

            Enumerable.Range(1, NumRows).ToList().ForEach(i =>
            {
                rowHeights.Add(rowHeightToRepeat);
                rowUnitTypes.Add(rowUnitTypeToRepeat);
            });

            GridSettings gs = new GridSettings()
            {
                NumColumns = NumColumns,
                NumRows = NumRows,
                ColWidths = colWidths,
                ColUnitTypes = colUnitTypes,
                RowHeights = rowHeights,
                RowUnitTypes = rowUnitTypes,
                Height = height,
                Width = width
            };
            chain.StoreSetting<T>("GridSettings", gs);
            return chain;
        }
        public static GridSettings CompositeGridDimensions<T>(this T chain, double width, double height, int NumRows, int NumColumns, double colWidth1, GridUnitType unitType1,
           double colWidth2 = 9999999999D, GridUnitType unitType2 = GridUnitType.Auto,
           double colWidth3 = 9999999999D, GridUnitType unitType3 = GridUnitType.Auto,
           double colWidth4 = 9999999999D, GridUnitType unitType4 = GridUnitType.Auto,
           double colWidth5 = 9999999999D, GridUnitType unitType5 = GridUnitType.Auto,
           double colWidth6 = 9999999999D, GridUnitType unitType6 = GridUnitType.Auto,
           double colWidth7 = 9999999999D, GridUnitType unitType7 = GridUnitType.Auto,
           double colWidth8 = 9999999999D, GridUnitType unitType8 = GridUnitType.Auto,
           double colWidth9 = 9999999999D, GridUnitType unitType9 = GridUnitType.Auto,
           double colWidth10 = 9999999999D, GridUnitType unitType10 = GridUnitType.Auto,
           double colWidth11 = 9999999999D, GridUnitType unitType11 = GridUnitType.Auto,
           double colWidth12 = 9999999999D, GridUnitType unitType12 = GridUnitType.Auto,
           double colWidth13 = 9999999999D, GridUnitType unitType13 = GridUnitType.Auto,
           double colWidth14 = 9999999999D, GridUnitType unitType14 = GridUnitType.Auto,
           double colWidth15 = 9999999999D, GridUnitType unitType15 = GridUnitType.Auto,
           double colWidth16 = 9999999999D, GridUnitType unitType16 = GridUnitType.Auto,
           double colWidth17 = 9999999999D, GridUnitType unitType17 = GridUnitType.Auto,
           double colWidth18 = 9999999999D, GridUnitType unitType18 = GridUnitType.Auto,
           double colWidth19 = 9999999999D, GridUnitType unitType19 = GridUnitType.Auto,
           double colWidth20 = 9999999999D, GridUnitType unitType20 = GridUnitType.Auto,
           double colWidth21 = 9999999999D, GridUnitType unitType21 = GridUnitType.Auto,
           double colWidth22 = 9999999999D, GridUnitType unitType22 = GridUnitType.Auto,
           double colWidth23 = 9999999999D, GridUnitType unitType23 = GridUnitType.Auto,
           double colWidth24 = 9999999999D, GridUnitType unitType24 = GridUnitType.Auto,
           double colWidth25 = 9999999999D, GridUnitType unitType25 = GridUnitType.Auto)
            where T : FrameworkElement
        {
            List<double> colWidths = new List<double>();
            List<GridUnitType> colUnitTypes = new List<GridUnitType>();
            colWidths.Add(colWidth1);
            colUnitTypes.Add(unitType1);

            if (colWidth2 != 9999999999D) { colWidths.Add(colWidth2); colUnitTypes.Add(unitType2); }
            if (colWidth3 != 9999999999D) { colWidths.Add(colWidth3); colUnitTypes.Add(unitType3); }
            if (colWidth4 != 9999999999D) { colWidths.Add(colWidth4); colUnitTypes.Add(unitType4); }
            if (colWidth5 != 9999999999D) { colWidths.Add(colWidth5); colUnitTypes.Add(unitType5); }
            if (colWidth6 != 9999999999D) { colWidths.Add(colWidth6); colUnitTypes.Add(unitType6); }
            if (colWidth7 != 9999999999D) { colWidths.Add(colWidth7); colUnitTypes.Add(unitType7); }
            if (colWidth8 != 9999999999D) { colWidths.Add(colWidth8); colUnitTypes.Add(unitType8); }
            if (colWidth9 != 9999999999D) { colWidths.Add(colWidth9); colUnitTypes.Add(unitType9); }
            if (colWidth10 != 9999999999D) { colWidths.Add(colWidth10); colUnitTypes.Add(unitType10); }
            if (colWidth11 != 9999999999D) { colWidths.Add(colWidth11); colUnitTypes.Add(unitType11); }
            if (colWidth12 != 9999999999D) { colWidths.Add(colWidth12); colUnitTypes.Add(unitType12); }
            if (colWidth13 != 9999999999D) { colWidths.Add(colWidth13); colUnitTypes.Add(unitType13); }
            if (colWidth14 != 9999999999D) { colWidths.Add(colWidth14); colUnitTypes.Add(unitType14); }
            if (colWidth15 != 9999999999D) { colWidths.Add(colWidth15); colUnitTypes.Add(unitType15); }
            if (colWidth16 != 9999999999D) { colWidths.Add(colWidth16); colUnitTypes.Add(unitType16); }
            if (colWidth17 != 9999999999D) { colWidths.Add(colWidth17); colUnitTypes.Add(unitType17); }
            if (colWidth18 != 9999999999D) { colWidths.Add(colWidth18); colUnitTypes.Add(unitType18); }
            if (colWidth19 != 9999999999D) { colWidths.Add(colWidth19); colUnitTypes.Add(unitType19); }
            if (colWidth20 != 9999999999D) { colWidths.Add(colWidth20); colUnitTypes.Add(unitType20); }
            if (colWidth21 != 9999999999D) { colWidths.Add(colWidth21); colUnitTypes.Add(unitType21); }
            if (colWidth22 != 9999999999D) { colWidths.Add(colWidth22); colUnitTypes.Add(unitType22); }
            if (colWidth23 != 9999999999D) { colWidths.Add(colWidth23); colUnitTypes.Add(unitType23); }
            if (colWidth24 != 9999999999D) { colWidths.Add(colWidth24); colUnitTypes.Add(unitType24); }
            if (colWidth25 != 9999999999D) { colWidths.Add(colWidth25); colUnitTypes.Add(unitType25); }

            GridSettings gs = new GridSettings()
            {
                NumColumns =
                    NumColumns,
                NumRows = NumRows,
                ColWidths = colWidths,
                ColUnitTypes =
                    colUnitTypes
            };

            return gs;
        }

        public static GridSettings CompositeGridDimensions<T>(this T chain, int NumRows, int NumColumns, double rowHeightToRepeat, GridUnitType rowUnitTypeToRepeat, double colWidth1, GridUnitType unitType1,
            double colWidth2 = 9999999999D, GridUnitType unitType2 = GridUnitType.Auto,
            double colWidth3 = 9999999999D, GridUnitType unitType3 = GridUnitType.Auto,
            double colWidth4 = 9999999999D, GridUnitType unitType4 = GridUnitType.Auto,
            double colWidth5 = 9999999999D, GridUnitType unitType5 = GridUnitType.Auto,
            double colWidth6 = 9999999999D, GridUnitType unitType6 = GridUnitType.Auto,
            double colWidth7 = 9999999999D, GridUnitType unitType7 = GridUnitType.Auto,
            double colWidth8 = 9999999999D, GridUnitType unitType8 = GridUnitType.Auto,
            double colWidth9 = 9999999999D, GridUnitType unitType9 = GridUnitType.Auto,
            double colWidth10 = 9999999999D, GridUnitType unitType10 = GridUnitType.Auto,
            double colWidth11 = 9999999999D, GridUnitType unitType11 = GridUnitType.Auto,
            double colWidth12 = 9999999999D, GridUnitType unitType12 = GridUnitType.Auto,
            double colWidth13 = 9999999999D, GridUnitType unitType13 = GridUnitType.Auto,
            double colWidth14 = 9999999999D, GridUnitType unitType14 = GridUnitType.Auto,
            double colWidth15 = 9999999999D, GridUnitType unitType15 = GridUnitType.Auto,
            double colWidth16 = 9999999999D, GridUnitType unitType16 = GridUnitType.Auto,
            double colWidth17 = 9999999999D, GridUnitType unitType17 = GridUnitType.Auto,
            double colWidth18 = 9999999999D, GridUnitType unitType18 = GridUnitType.Auto,
            double colWidth19 = 9999999999D, GridUnitType unitType19 = GridUnitType.Auto,
            double colWidth20 = 9999999999D, GridUnitType unitType20 = GridUnitType.Auto,
            double colWidth21 = 9999999999D, GridUnitType unitType21 = GridUnitType.Auto,
            double colWidth22 = 9999999999D, GridUnitType unitType22 = GridUnitType.Auto,
            double colWidth23 = 9999999999D, GridUnitType unitType23 = GridUnitType.Auto,
            double colWidth24 = 9999999999D, GridUnitType unitType24 = GridUnitType.Auto,
            double colWidth25 = 9999999999D, GridUnitType unitType25 = GridUnitType.Auto)
             where T : FrameworkElement
        {
            List<double> colWidths = new List<double>();
            List<GridUnitType> colUnitTypes = new List<GridUnitType>();
            colWidths.Add(colWidth1);
            colUnitTypes.Add(unitType1);

            List<double> rowHeights = new List<double>();
            List<GridUnitType> rowUnitTypes = new List<GridUnitType>();

            if (colWidth2 != 9999999999D) { colWidths.Add(colWidth2); colUnitTypes.Add(unitType2); }
            if (colWidth3 != 9999999999D) { colWidths.Add(colWidth3); colUnitTypes.Add(unitType3); }
            if (colWidth4 != 9999999999D) { colWidths.Add(colWidth4); colUnitTypes.Add(unitType4); }
            if (colWidth5 != 9999999999D) { colWidths.Add(colWidth5); colUnitTypes.Add(unitType5); }
            if (colWidth6 != 9999999999D) { colWidths.Add(colWidth6); colUnitTypes.Add(unitType6); }
            if (colWidth7 != 9999999999D) { colWidths.Add(colWidth7); colUnitTypes.Add(unitType7); }
            if (colWidth8 != 9999999999D) { colWidths.Add(colWidth8); colUnitTypes.Add(unitType8); }
            if (colWidth9 != 9999999999D) { colWidths.Add(colWidth9); colUnitTypes.Add(unitType9); }
            if (colWidth10 != 9999999999D) { colWidths.Add(colWidth10); colUnitTypes.Add(unitType10); }
            if (colWidth11 != 9999999999D) { colWidths.Add(colWidth11); colUnitTypes.Add(unitType11); }
            if (colWidth12 != 9999999999D) { colWidths.Add(colWidth12); colUnitTypes.Add(unitType12); }
            if (colWidth13 != 9999999999D) { colWidths.Add(colWidth13); colUnitTypes.Add(unitType13); }
            if (colWidth14 != 9999999999D) { colWidths.Add(colWidth14); colUnitTypes.Add(unitType14); }
            if (colWidth15 != 9999999999D) { colWidths.Add(colWidth15); colUnitTypes.Add(unitType15); }
            if (colWidth16 != 9999999999D) { colWidths.Add(colWidth16); colUnitTypes.Add(unitType16); }
            if (colWidth17 != 9999999999D) { colWidths.Add(colWidth17); colUnitTypes.Add(unitType17); }
            if (colWidth18 != 9999999999D) { colWidths.Add(colWidth18); colUnitTypes.Add(unitType18); }
            if (colWidth19 != 9999999999D) { colWidths.Add(colWidth19); colUnitTypes.Add(unitType19); }
            if (colWidth20 != 9999999999D) { colWidths.Add(colWidth20); colUnitTypes.Add(unitType20); }
            if (colWidth21 != 9999999999D) { colWidths.Add(colWidth21); colUnitTypes.Add(unitType21); }
            if (colWidth22 != 9999999999D) { colWidths.Add(colWidth22); colUnitTypes.Add(unitType22); }
            if (colWidth23 != 9999999999D) { colWidths.Add(colWidth23); colUnitTypes.Add(unitType23); }
            if (colWidth24 != 9999999999D) { colWidths.Add(colWidth24); colUnitTypes.Add(unitType24); }
            if (colWidth25 != 9999999999D) { colWidths.Add(colWidth25); colUnitTypes.Add(unitType25); }           

            Enumerable.Range(1, NumRows).ToList().ForEach(i =>
            {
                rowHeights.Add(rowHeightToRepeat);
                rowUnitTypes.Add(rowUnitTypeToRepeat);
            });

            GridSettings gs = new GridSettings()
            {
                NumColumns =
                    NumColumns,
                NumRows = NumRows,
                RowHeights = rowHeights,
                RowUnitTypes = rowUnitTypes,
                ColWidths = colWidths,
                ColUnitTypes =
                    colUnitTypes
            };

            return gs;
        }

        public static T SetCompositeGridDimensionsWithRowHt<T>(this T chain, double width, double height, int NumRows, int NumColumns, double rowHeightToRepeat, GridUnitType rowUnitTypeToRepeat, double colWidth1, GridUnitType unitType1,
            double colWidth2 = 9999999999D, GridUnitType unitType2 = GridUnitType.Auto,
            double colWidth3 = 9999999999D, GridUnitType unitType3 = GridUnitType.Auto,
            double colWidth4 = 9999999999D, GridUnitType unitType4 = GridUnitType.Auto,
            double colWidth5 = 9999999999D, GridUnitType unitType5 = GridUnitType.Auto,
            double colWidth6 = 9999999999D, GridUnitType unitType6 = GridUnitType.Auto,
            double colWidth7 = 9999999999D, GridUnitType unitType7 = GridUnitType.Auto,
            double colWidth8 = 9999999999D, GridUnitType unitType8 = GridUnitType.Auto,
            double colWidth9 = 9999999999D, GridUnitType unitType9 = GridUnitType.Auto,
            double colWidth10 = 9999999999D, GridUnitType unitType10 = GridUnitType.Auto,
            double colWidth11 = 9999999999D, GridUnitType unitType11 = GridUnitType.Auto,
            double colWidth12 = 9999999999D, GridUnitType unitType12 = GridUnitType.Auto,
            double colWidth13 = 9999999999D, GridUnitType unitType13 = GridUnitType.Auto,
            double colWidth14 = 9999999999D, GridUnitType unitType14 = GridUnitType.Auto,
            double colWidth15 = 9999999999D, GridUnitType unitType15 = GridUnitType.Auto,
            double colWidth16 = 9999999999D, GridUnitType unitType16 = GridUnitType.Auto,
            double colWidth17 = 9999999999D, GridUnitType unitType17 = GridUnitType.Auto,
            double colWidth18 = 9999999999D, GridUnitType unitType18 = GridUnitType.Auto,
            double colWidth19 = 9999999999D, GridUnitType unitType19 = GridUnitType.Auto,
            double colWidth20 = 9999999999D, GridUnitType unitType20 = GridUnitType.Auto,
            double colWidth21 = 9999999999D, GridUnitType unitType21 = GridUnitType.Auto,
            double colWidth22 = 9999999999D, GridUnitType unitType22 = GridUnitType.Auto,
            double colWidth23 = 9999999999D, GridUnitType unitType23 = GridUnitType.Auto,
            double colWidth24 = 9999999999D, GridUnitType unitType24 = GridUnitType.Auto,
            double colWidth25 = 9999999999D, GridUnitType unitType25 = GridUnitType.Auto)
             where T : FrameworkElement
        {
            List<double> colWidths = new List<double>();
            List<GridUnitType> colUnitTypes = new List<GridUnitType>();
            colWidths.Add(colWidth1);
            colUnitTypes.Add(unitType1);

            List<double> rowHeights = new List<double>();
            List<GridUnitType> rowUnitTypes = new List<GridUnitType>();

            if (colWidth2 != 9999999999D) { colWidths.Add(colWidth2); colUnitTypes.Add(unitType2); }
            if (colWidth3 != 9999999999D) { colWidths.Add(colWidth3); colUnitTypes.Add(unitType3); }
            if (colWidth4 != 9999999999D) { colWidths.Add(colWidth4); colUnitTypes.Add(unitType4); }
            if (colWidth5 != 9999999999D) { colWidths.Add(colWidth5); colUnitTypes.Add(unitType5); }
            if (colWidth6 != 9999999999D) { colWidths.Add(colWidth6); colUnitTypes.Add(unitType6); }
            if (colWidth7 != 9999999999D) { colWidths.Add(colWidth7); colUnitTypes.Add(unitType7); }
            if (colWidth8 != 9999999999D) { colWidths.Add(colWidth8); colUnitTypes.Add(unitType8); }
            if (colWidth9 != 9999999999D) { colWidths.Add(colWidth9); colUnitTypes.Add(unitType9); }
            if (colWidth10 != 9999999999D) { colWidths.Add(colWidth10); colUnitTypes.Add(unitType10); }
            if (colWidth11 != 9999999999D) { colWidths.Add(colWidth11); colUnitTypes.Add(unitType11); }
            if (colWidth12 != 9999999999D) { colWidths.Add(colWidth12); colUnitTypes.Add(unitType12); }
            if (colWidth13 != 9999999999D) { colWidths.Add(colWidth13); colUnitTypes.Add(unitType13); }
            if (colWidth14 != 9999999999D) { colWidths.Add(colWidth14); colUnitTypes.Add(unitType14); }
            if (colWidth15 != 9999999999D) { colWidths.Add(colWidth15); colUnitTypes.Add(unitType15); }
            if (colWidth16 != 9999999999D) { colWidths.Add(colWidth16); colUnitTypes.Add(unitType16); }
            if (colWidth17 != 9999999999D) { colWidths.Add(colWidth17); colUnitTypes.Add(unitType17); }
            if (colWidth18 != 9999999999D) { colWidths.Add(colWidth18); colUnitTypes.Add(unitType18); }
            if (colWidth19 != 9999999999D) { colWidths.Add(colWidth19); colUnitTypes.Add(unitType19); }
            if (colWidth20 != 9999999999D) { colWidths.Add(colWidth20); colUnitTypes.Add(unitType20); }
            if (colWidth21 != 9999999999D) { colWidths.Add(colWidth21); colUnitTypes.Add(unitType21); }
            if (colWidth22 != 9999999999D) { colWidths.Add(colWidth22); colUnitTypes.Add(unitType22); }
            if (colWidth23 != 9999999999D) { colWidths.Add(colWidth23); colUnitTypes.Add(unitType23); }
            if (colWidth24 != 9999999999D) { colWidths.Add(colWidth24); colUnitTypes.Add(unitType24); }
            if (colWidth25 != 9999999999D) { colWidths.Add(colWidth25); colUnitTypes.Add(unitType25); }

            Enumerable.Range(1, NumRows).ToList().ForEach(i =>
            {
                rowHeights.Add(rowHeightToRepeat);
                rowUnitTypes.Add(rowUnitTypeToRepeat);
            });

            GridSettings gs = new GridSettings()
            {
                NumColumns = NumColumns,
                NumRows = NumRows,
                ColWidths = colWidths,
                RowHeights = rowHeights,
                RowUnitTypes = rowUnitTypes,
                ColUnitTypes = colUnitTypes,
                Height = height,
                Width = width
            };
            chain.StoreSetting<T>("GridSettings", gs);
            return chain;
        }
        
        public static T SetCompositeGridDimensions<T>(this T chain, double width, double height, int NumRows, int NumColumns, double colWidth1, GridUnitType unitType1,
            double colWidth2 = 9999999999D, GridUnitType unitType2 = GridUnitType.Auto,
            double colWidth3 = 9999999999D, GridUnitType unitType3 = GridUnitType.Auto,
            double colWidth4 = 9999999999D, GridUnitType unitType4 = GridUnitType.Auto,
            double colWidth5 = 9999999999D, GridUnitType unitType5 = GridUnitType.Auto,
            double colWidth6 = 9999999999D, GridUnitType unitType6 = GridUnitType.Auto,
            double colWidth7 = 9999999999D, GridUnitType unitType7 = GridUnitType.Auto,
            double colWidth8 = 9999999999D, GridUnitType unitType8 = GridUnitType.Auto,
            double colWidth9 = 9999999999D, GridUnitType unitType9 = GridUnitType.Auto,
            double colWidth10 = 9999999999D, GridUnitType unitType10 = GridUnitType.Auto,
            double colWidth11 = 9999999999D, GridUnitType unitType11 = GridUnitType.Auto,
            double colWidth12 = 9999999999D, GridUnitType unitType12 = GridUnitType.Auto,
            double colWidth13 = 9999999999D, GridUnitType unitType13 = GridUnitType.Auto,
            double colWidth14 = 9999999999D, GridUnitType unitType14 = GridUnitType.Auto,
            double colWidth15 = 9999999999D, GridUnitType unitType15 = GridUnitType.Auto,
            double colWidth16 = 9999999999D, GridUnitType unitType16 = GridUnitType.Auto,
            double colWidth17 = 9999999999D, GridUnitType unitType17 = GridUnitType.Auto,
            double colWidth18 = 9999999999D, GridUnitType unitType18 = GridUnitType.Auto,
            double colWidth19 = 9999999999D, GridUnitType unitType19 = GridUnitType.Auto,
            double colWidth20 = 9999999999D, GridUnitType unitType20 = GridUnitType.Auto,
            double colWidth21 = 9999999999D, GridUnitType unitType21 = GridUnitType.Auto,
            double colWidth22 = 9999999999D, GridUnitType unitType22 = GridUnitType.Auto,
            double colWidth23 = 9999999999D, GridUnitType unitType23 = GridUnitType.Auto,
            double colWidth24 = 9999999999D, GridUnitType unitType24 = GridUnitType.Auto,
            double colWidth25 = 9999999999D, GridUnitType unitType25 = GridUnitType.Auto)
             where T : FrameworkElement
        {
            List<double> colWidths = new List<double>();
            List<GridUnitType> colUnitTypes = new List<GridUnitType>();
            colWidths.Add(colWidth1);
            colUnitTypes.Add(unitType1);
            if (colWidth2 != 9999999999D) { colWidths.Add(colWidth2); colUnitTypes.Add(unitType2); }
            if (colWidth3 != 9999999999D) { colWidths.Add(colWidth3); colUnitTypes.Add(unitType3); }
            if (colWidth4 != 9999999999D) { colWidths.Add(colWidth4); colUnitTypes.Add(unitType4); }
            if (colWidth5 != 9999999999D) { colWidths.Add(colWidth5); colUnitTypes.Add(unitType5); }
            if (colWidth6 != 9999999999D) { colWidths.Add(colWidth6); colUnitTypes.Add(unitType6); }
            if (colWidth7 != 9999999999D) { colWidths.Add(colWidth7); colUnitTypes.Add(unitType7); }
            if (colWidth8 != 9999999999D) { colWidths.Add(colWidth8); colUnitTypes.Add(unitType8); }
            if (colWidth9 != 9999999999D) { colWidths.Add(colWidth9); colUnitTypes.Add(unitType9); }
            if (colWidth10 != 9999999999D) { colWidths.Add(colWidth10); colUnitTypes.Add(unitType10); }
            if (colWidth11 != 9999999999D) { colWidths.Add(colWidth11); colUnitTypes.Add(unitType11); }
            if (colWidth12 != 9999999999D) { colWidths.Add(colWidth12); colUnitTypes.Add(unitType12); }
            if (colWidth13 != 9999999999D) { colWidths.Add(colWidth13); colUnitTypes.Add(unitType13); }
            if (colWidth14 != 9999999999D) { colWidths.Add(colWidth14); colUnitTypes.Add(unitType14); }
            if (colWidth15 != 9999999999D) { colWidths.Add(colWidth15); colUnitTypes.Add(unitType15); }
            if (colWidth16 != 9999999999D) { colWidths.Add(colWidth16); colUnitTypes.Add(unitType16); }
            if (colWidth17 != 9999999999D) { colWidths.Add(colWidth17); colUnitTypes.Add(unitType17); }
            if (colWidth18 != 9999999999D) { colWidths.Add(colWidth18); colUnitTypes.Add(unitType18); }
            if (colWidth19 != 9999999999D) { colWidths.Add(colWidth19); colUnitTypes.Add(unitType19); }
            if (colWidth20 != 9999999999D) { colWidths.Add(colWidth20); colUnitTypes.Add(unitType20); }
            if (colWidth21 != 9999999999D) { colWidths.Add(colWidth21); colUnitTypes.Add(unitType21); }
            if (colWidth22 != 9999999999D) { colWidths.Add(colWidth22); colUnitTypes.Add(unitType22); }
            if (colWidth23 != 9999999999D) { colWidths.Add(colWidth23); colUnitTypes.Add(unitType23); }
            if (colWidth24 != 9999999999D) { colWidths.Add(colWidth24); colUnitTypes.Add(unitType24); }
            if (colWidth25 != 9999999999D) { colWidths.Add(colWidth25); colUnitTypes.Add(unitType25); }

            GridSettings gs = new GridSettings()
            {
                NumColumns = NumColumns,
                NumRows = NumRows,
                ColWidths = colWidths,
                ColUnitTypes = colUnitTypes
            };
            chain.StoreSetting<T>("GridSettings", gs);
            return chain;
        }

        #endregion

        #region Text Settings

        #region TextBlock

        public static T SetFont<T>(this T chain, int row, int column, string family, double fontSize, FontWeight weights, FontStyle fontStyle) where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "FontFamily", new FontFamily(family));
            chain.Set<TextBlock, T>(row, column, "FontSize", fontSize);
            chain.Set<TextBlock, T>(row, column, "FontWeight", weights);
            chain.Set<TextBlock, T>(row, column, "FontStyle", fontStyle);

            return chain;
        }

        public static T SetFont<T>(this T chain, int row, int column, string family, double fontSize, FontWeight weights, FontStyle fontStyle, TextDecorationCollection textDecorations) where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "FontFamily", new FontFamily(family));
            chain.Set<TextBlock, T>(row, column, "FontSize", fontSize);
            chain.Set<TextBlock, T>(row, column, "FontWeight", weights);
            chain.Set<TextBlock, T>(row, column, "FontStyle", fontStyle);
            chain.Set<TextBlock, T>(row, column, "TextDecorations", textDecorations);

            return chain;
        }

        public static T CreateFontStyleKey<T>(this T chain, string styleKey, string family, double fontSize, FontWeight weights,
FontStyle fontStyle)
            where T : FrameworkElement
        {

            chain.StoreSetting<T>(styleKey + "Font", FontExt.CreateFont(family, fontSize, weights, fontStyle));

            return chain;
        }

        public static T CreateColorStyleKey<T>(this T chain, string styleKey, Brush newBrush)
            where T : FrameworkElement
        {
            chain.StoreSetting<T>(styleKey + "Color", newBrush);

            return chain;
        }

        public static T CreateColorStyleKey<T>(this T chain, string styleKey, byte red, byte green, byte blue, byte alpha) where T : FrameworkElement
        {
            Brush newBrush = (Brush)(new System.Windows.Media.SolidColorBrush(new
System.Windows.Media.Color()
            {
                R = red,
                G = green,
                B = blue,
                A = alpha
            }));
            chain.StoreSetting<T>(styleKey + "Color", newBrush);

            return chain;
        }

        public static T SetLineColorRange<T>(this T chain,
int rowStart, int rowCount, int column, Brush brush)
                 where T : FrameworkElement
        {
            Enumerable.Range(rowStart, rowCount).ToList().ForEach(innerInt =>
            {
                chain.Set<TextBlock, T>(innerInt, column, "Foreground", brush);
            });

            return chain;
        }

        public static T SetTextMaxHeight<T>(this T chain, int row, int column, double maxHeight)
                     where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "MaxHeight", maxHeight);
            return chain;
        }

        public static T SetTextMaxWidth<T>(this T chain, int row, int column, double maxWidth)
                     where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "MaxWidth", maxWidth);
            return chain;
        }

        public static T SetTextMinHeight<T>(this T chain, int row, int column, double minHeight)
             where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "MinHeight", minHeight);
            return chain;
        }

        public static T SetTextMinWidth<T>(this T chain, int row, int column, double minWidth)
                     where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "MinWidth", minWidth);
            return chain;
        }

        public static T SetTextColor<T>(this T chain, int row, int column, Brush brush)
                     where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "Foreground", brush);
            return chain;
        }

        public static T SetTextColorForLabel<T>(this T chain, int row, int column, Brush brush)
             where T : FrameworkElement
        {
            chain.Set<Label, T>(row, column, "Foreground", brush);
            return chain;
        }

        public static T SetTextColor<T>(this T chain, int row, int column, byte red, byte green, byte blue, byte alpha) where T : FrameworkElement
        {
            Brush newBrush = BrushExt.CreateSolidColorBrushFromRGB(red, green, blue, alpha);

            chain.Set<TextBlock, T>(row, column, "Foreground", newBrush);
            return chain;
        }

        public static T SetTextColorByStyleKey<T>(this T chain, string styleKey, int row, int column)
                     where T : FrameworkElement
        {
            Brush newBrush = SettingsManager.GetSetting<T, Brush>(chain, styleKey = styleKey + "Color");
            chain.Set<TextBlock, T>(row, column, "Foreground", newBrush);
            return chain;
        }

        public static T SetTextColorToColByStyleKey<T>(this T chain, string styleKey, int column, int rowStart, int rowCount) where T : FrameworkElement
        {
            Brush newBrush = SettingsManager.GetSetting<T, Brush>(chain, styleKey = styleKey + "Color");

            Enumerable.Range(rowStart, rowCount).ToList().ForEach(innerInt =>
            {
                chain.Set<TextBlock, T>(innerInt, column, "Foreground", newBrush);
            });

            return chain;
        }

        public static T SetTextColorToRowByStyleKey<T>(this T chain, string styleKey, int row, int colStart, int colCount) where T : FrameworkElement
        {
            Brush newBrush = SettingsManager.GetSetting<T, Brush>(chain, styleKey = styleKey + "Color");

            Enumerable.Range(colStart, colCount).ToList().ForEach(innerInt =>
            {
                chain.Set<TextBlock, T>(row, innerInt, "Foreground", newBrush);
            });

            return chain;
        }

        public static T SetTextColorToCol<T>(this T chain, int column, int rowStart, int rowCount, Brush newBrush)
                     where T : FrameworkElement
        {
            Enumerable.Range(rowStart, rowCount).ToList().ForEach(innerInt =>
            {
                chain.Set<TextBlock, T>(innerInt, column, "Foreground", newBrush);
            });

            return chain;
        }

        public static T SetTextColorToRow<T>(this T chain, int row, int colStart, int colCount, Brush newBrush)
                     where T : FrameworkElement
        {
            Enumerable.Range(colStart, colCount).ToList().ForEach(innerInt =>
            {
                chain.Set<TextBlock, T>(row, innerInt, "Foreground", newBrush);
            });

            return chain;
        }

        public static T SetTextColorToCol<T>(this T chain, int column, int rowStart, int rowCount, byte red, byte green, byte blue, byte alpha) where T : FrameworkElement
        {
            Brush newBrush = BrushExt.CreateSolidColorBrushFromRGB(red, green, blue, alpha);

            Enumerable.Range(rowStart, rowCount).ToList().ForEach(innerInt =>
            {
                chain.Set<TextBlock, T>(innerInt, column, "Foreground", newBrush);
            });

            return chain;
        }

        public static T SetTextColorToRow<T>(this T chain, int row, int colStart, int colCount, byte red, byte green, byte blue, byte alpha) where T : FrameworkElement
        {
            Brush newBrush = BrushExt.CreateSolidColorBrushFromRGB(red, green, blue, alpha);

            Enumerable.Range(colStart, colCount).ToList().ForEach(innerInt =>
            {
                chain.Set<TextBlock, T>(row, innerInt, "Foreground", newBrush);
            });

            return chain;
        }
        
        public static T SetFontByStyleKey<T>(this T chain, string styleKey, int row, int column)
             where T : FrameworkElement
        {
            FontSettings fs = SettingsManager.GetSetting<T, FontSettings>(chain, styleKey = styleKey + "Font");
            chain.SetFont<T>(row, column, fs.FontFamily, fs.FontSize, fs.FontWeight, fs.FontStyle);
            return chain;
        }

        public static T SetFontToColByStyleKey<T>(this T chain, string styleKey, int column, int rowStart, int rowCount)
             where T : FrameworkElement
        {
            FontSettings fs = SettingsManager.GetSetting<T, FontSettings>(chain, styleKey = styleKey + "Font");

            Enumerable.Range(rowStart, rowCount).ToList().ForEach(innerInt =>
            {
                chain.SetFont<T>(innerInt, column, fs.FontFamily, fs.FontSize, fs.FontWeight, fs.FontStyle);
            });

            return chain;
        }

        public static T SetFontToRowByStyleKey<T>(this T chain, string styleKey, int row, int colStart, int colCount) where T : FrameworkElement
        {
            FontSettings fs = SettingsManager.GetSetting<T, FontSettings>(chain, styleKey = styleKey + "Font");

            Enumerable.Range(colStart, colCount).ToList().ForEach(innerInt =>
            {
                chain.SetFont<T>(row, innerInt, fs.FontFamily, fs.FontSize, fs.FontWeight, fs.FontStyle);
            });

            return chain;
        }

        public static T SetFontToCol<T>(this T chain, int column, int rowStart, int rowCount, string family, double fontSize,
FontWeight weights, FontStyle fontStyle) where T : FrameworkElement
        {
            FontSettings fs = FontExt.CreateFont(family, fontSize, weights, fontStyle);

            Enumerable.Range(rowStart, rowCount).ToList().ForEach(innerInt =>
            {
                chain.SetFont<T>(innerInt, column, fs.FontFamily, fs.FontSize, fs.FontWeight, fs.FontStyle);
            });

            return chain;
        }

        public static T SetFontToRow<T>(this T chain, int row, int colStart, int colCount, string family, double fontSize,
FontWeight weights, FontStyle fontStyle) where T : FrameworkElement
        {
            FontSettings fs = FontExt.CreateFont(family, fontSize, weights, fontStyle);

            Enumerable.Range(colStart, colCount).ToList().ForEach(innerInt =>
            {
                chain.SetFont<T>(row, innerInt, fs.FontFamily, fs.FontSize, fs.FontWeight, fs.FontStyle);
            });

            return chain;
        }
        
        public static T SetTextWrapping<T>(this T chain, int row, int column, System.Windows.TextWrapping textWrap)
                     where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "TextWrapping", textWrap);
            return chain;
        }

        public static T SetTextBackground<T>(this T chain, int row, int column, Brush brush)
                                 where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "Background", brush);
            return chain;
        }

        public static T SetTextEffect<T>(this T chain, int row, int column, System.Windows.Media.Effects.Effect effect)
                         where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "Effect", effect);
            return chain;
        }

        public static T SetTextPadding<T>(this T chain, int row, int column, Thickness thickness)
    where T : FrameworkElement
        {          
            chain.Set<TextBlock, T>(row, column, "Padding", thickness);
            return chain;
        }

        public static T SetTextMargin<T>(this T chain, int row, int column, Thickness thickness)
where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "Margin", thickness);
            return chain;
        }

        public static T SetTextVisibility<T>(this T chain, int row, int column, Visibility visibility)
     where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "Visibility", visibility);
            return chain;
        }

        public static T SetVerticalAlignment<T>(this T chain, int row, int column, System.Windows.VerticalAlignment vertAlign) where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "VerticalAlignment", vertAlign);
            return chain;
        }

        public static T SetHorizontalAlignmentForText<T>(this T chain, int row, int column, TextAlignment horizAlignSetting)
            where T : FrameworkElement
        {
            chain.Set<TextBlock, T>(row, column, "TextAlignment", horizAlignSetting);
            return chain;
        }

        #endregion

        #region Label

        public static T SetHorizontalAlignmentForLabel<T>(this T chain, int row, int column, HorizontalAlignment horizAlignSetting)
    where T : FrameworkElement
        {
            chain.Set<Label, T>(row, column, "HorizontalContentAlignment", horizAlignSetting);
            return chain;
        }

        public static T SetFontOnLabel<T>(this T chain, int row, int column, string family, double fontSize, FontWeight weights, FontStyle fontStyle) where T : FrameworkElement
        {
            chain.Set<Label, T>(row, column, "FontFamily", new FontFamily(family));
            chain.Set<Label, T>(row, column, "FontSize", fontSize);
            chain.Set<Label, T>(row, column, "FontWeight", weights);
            chain.Set<Label, T>(row, column, "FontStyle", fontStyle);

            return chain;
        }

        public static T SetZIndex<K, T>(this T chain, int row, int column, int zIndex) 
            where K : FrameworkElement, new()
            where T : FrameworkElement
        {
            chain.SetAttachedProperty<K, T>("ZIndexProperty", row, column, obj => { obj.SetValue(Canvas.ZIndexProperty, zIndex); }); 

            return chain;
        }

        public static T RemoveZIndexSetting<K, T>(this T chain, int row, int column)
            where K : FrameworkElement, new()
            where T : FrameworkElement
        {
            chain.RemoveAttachedPropertySetting<K, T>("ZIndexProperty", row, column);

            return chain;
        }

        public static T SetFontToColForLabel<T>(this T chain, int column, int rowStart, int rowCount, string family, double fontSize,
FontWeight weights, FontStyle fontStyle) where T : FrameworkElement
        {
            FontSettings fs = FontExt.CreateFont(family, fontSize, weights, fontStyle);

            Enumerable.Range(rowStart, rowCount).ToList().ForEach(innerInt =>
            {
                chain.SetFontOnLabel<T>(innerInt, column, fs.FontFamily, fs.FontSize, fs.FontWeight, fs.FontStyle);
            });

            return chain;
        }

        public static T SetFontToRowForLabel<T>(this T chain, int row, int colStart, int colCount, string family, double fontSize,
FontWeight weights, FontStyle fontStyle) where T : FrameworkElement
        {
            FontSettings fs = FontExt.CreateFont(family, fontSize, weights, fontStyle);

            Enumerable.Range(colStart, colCount).ToList().ForEach(innerInt =>
            {
                chain.SetFontOnLabel<T>(row, innerInt, fs.FontFamily, fs.FontSize, fs.FontWeight, fs.FontStyle);
            });

            return chain;
        }
        
        #endregion

        #endregion
              
        #region Image Settings

        public static T SetImageHorizontalAlignment<T>(this T chain, int row, int column, HorizontalAlignment align)
                                 where T : FrameworkElement
        {
            chain.Set<Image, T>(row, column, "HorizontalAlignment", align);
            return chain;
        }

        public static T SetImageClip<T>(this T chain, int row, int column, Geometry geometryToClipBy)
                         where T : FrameworkElement
        {
            chain.Set<Image, T>(row, column, "Clip", geometryToClipBy);
            return chain;
        }

        public static T SetImageStretch<T>(this T chain, int row, int column, Stretch stretch)
                                 where T : FrameworkElement
        {
            chain.Set<Image, T>(row, column, "Stretch", stretch);
            return chain;
        }

        public static T SetImageStretchDirection<T>(this T chain, int row, int column, StretchDirection stretchDirection) where T : FrameworkElement
        {      
            chain.Set<Image, T>(row, column, "StretchDirection", stretchDirection);
            return chain;
        }

        public static T SetImageMargin<T>(this T chain, int row, int column, Thickness thickness)
                                 where T : FrameworkElement
        {  
            chain.Set<Image, T>(row, column, "Margin", thickness);
            return chain;
        }

        public static T SetImageVisibility<T>(this T chain, int row, int column, Visibility visibility)
                                 where T : FrameworkElement
        {
            chain.Set<Image, T>(row, column, "Visibility", visibility);
            return chain;
        }

        #endregion
        
        #endregion
        
        /// <summary>
        /// Set a Selector Class directly on Parent or any random FrameworkElement
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="selectorClassName"></param>
        public static void SetSelectorClass(this FrameworkElement chain, string selectorClassName)
        {
            chain.SetValue(SelectorClassSetting.SelectorClass1Property, selectorClassName);
        }

        /// <summary>
        ///  Set Selector Class 1 and 2 directly on Parent or any random FrameworkElement
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="selectorClassName1"></param>
        /// <param name="selectorClassName2"></param>
        public static void SetSelectorClass(this FrameworkElement chain, string selectorClassName1, string selectorClassName2)
        {
            chain.SetValue(SelectorClassSetting.SelectorClass1Property, selectorClassName1);
            chain.SetValue(SelectorClassSetting.SelectorClass2Property, selectorClassName2);
        }

        /// <summary>
        /// Set Selector Class 1, 2, and 3 directly on Parent or any random FrameworkElement
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="selectorClassName1"></param>
        /// <param name="selectorClassName2"></param>
        /// <param name="selectorClassName3"></param>
        public static void SetSelectorClass(this FrameworkElement chain, string selectorClassName1, string selectorClassName2, string selectorClassName3)
        {
            chain.SetValue(SelectorClassSetting.SelectorClass1Property, selectorClassName1);
            chain.SetValue(SelectorClassSetting.SelectorClass2Property, selectorClassName2);
            chain.SetValue(SelectorClassSetting.SelectorClass3Property, selectorClassName3);
        }      

        /// <summary>
        /// Set a Selector Class at X-Y (row, column)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="selectorClassName"></param>
        /// <returns></returns>
        public static SettingsChain<T> SetSelectorClass<T>(this SettingsChain<T> chain, int row, int column, string selectorClassName)
            where T : FrameworkElement
        {
            return SetSelectorClass1<T>(chain, row, column, selectorClassName);
        }

        /// <summary>
        /// Set a Selector Class starting at rowStart and counting for rowCount, at column.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="column"></param>
        /// <param name="rowStart"></param>
        /// <param name="rowCount"></param>
        /// <param name="selectorClassName"></param>
        /// <returns></returns>
        public static SettingsChain<T> SetSelectorClassToCol<T>(this SettingsChain<T> chain, int column, int rowStart, int rowCount, string selectorClassName)
            where T : FrameworkElement
        {
            return SetSelectorClass1ToCol<T>(chain, column, rowStart, rowCount, selectorClassName);
        }

        /// <summary>
        /// Set a Selector Class starting at rowStart and counting for rowCount, at column.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="column"></param>
        /// <param name="rowStart"></param>
        /// <param name="rowCount"></param>
        /// <param name="selectorClassName"></param>
        /// <returns></returns>
        private static SettingsChain<T> SetSelectorClass1ToCol<T>(this SettingsChain<T> chain, int column, int rowStart, int rowCount, string selectorClassName)
            where T : FrameworkElement
        {
            Enumerable.Range(rowStart, rowCount).ToList().ForEach(innerInt =>
            {
                chain.SetAttachedProperty<FrameworkElement, T>("SelectorClass1", innerInt, column, obj => { obj.SetValue(SelectorClassSetting.SelectorClass1Property, selectorClassName); });
            });

            return chain;
        }

        /// <summary>
        /// Set a Selector Class starting at colStart and counting for colCount, at row.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="column"></param>
        /// <param name="rowStart"></param>
        /// <param name="rowCount"></param>
        /// <param name="selectorClassName"></param>
        /// <returns></returns>
        public static SettingsChain<T> SetSelectorClassToRow<T>(this SettingsChain<T> chain, int row, int colStart, int colCount, string selectorClassName)
            where T : FrameworkElement
        {
            return SetSelectorClass1ToRow<T>(chain, row, colStart, colCount, selectorClassName);
        }

        /// <summary>
        /// Set a Selector Class starting at colStart and counting for colCount, at row.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="column"></param>
        /// <param name="rowStart"></param>
        /// <param name="rowCount"></param>
        /// <param name="selectorClassName"></param>
        /// <returns></returns>
        private static SettingsChain<T> SetSelectorClass1ToRow<T>(this SettingsChain<T> chain, int row, int colStart, int colCount, string selectorClassName)
            where T : FrameworkElement
        {
            Enumerable.Range(colStart, colCount).ToList().ForEach(innerInt =>
            {
                chain.SetAttachedProperty<FrameworkElement, T>("SelectorClass1", row, innerInt, obj => { obj.SetValue(SelectorClassSetting.SelectorClass1Property, selectorClassName); });
            });

            return chain;
        }

        /// <summary>
        /// Set a Selector Class at X-Y (row, column)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="selectorClassName"></param>
        /// <returns></returns>
        public static SettingsChain<T> SetSelectorClass<T>(this SettingsChain<T> chain, int row, int column, string selectorClassName1, string selectorClassName2)
            where T : FrameworkElement
        {
            return SetSelectorClass1<T>(chain, row, column, selectorClassName1).SetSelectorClass2<T>(row, column, selectorClassName2);
        }

        /// <summary>
        /// Set a Selector Class at X-Y (row, column)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="selectorClassName"></param>
        /// <returns></returns>
        public static SettingsChain<T> SetSelectorClass<T>(this SettingsChain<T> chain, int row, int column, string selectorClassName1, string selectorClassName2, string selectorClassName3)
            where T : FrameworkElement
        {
            return SetSelectorClass1<T>(chain, row, column, selectorClassName1).SetSelectorClass2<T>(row, column, selectorClassName2).SetSelectorClass3<T>(row, column, selectorClassName3);
        }

        /// <summary>
        /// Set a Selector Class at X-Y (row, column)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="selectorClassName"></param>
        /// <returns></returns>
        private static SettingsChain<T> SetSelectorClass1<T>(this SettingsChain<T> chain, int row, int column, string selectorClassName)
            where T : FrameworkElement
        {
            return chain.SetAttachedProperty<FrameworkElement, T>("SelectorClass1", row, column, obj => { obj.SetValue(SelectorClassSetting.SelectorClass1Property, selectorClassName); });
        }

        /// <summary>
        /// Set a 2nd Selector Class at X-Y (row, column)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="selectorClassName"></param>
        /// <returns></returns>
        private static SettingsChain<T> SetSelectorClass2<T>(this SettingsChain<T> chain, int row, int column, string selectorClassName)
            where T : FrameworkElement
        {
            return chain.SetAttachedProperty<FrameworkElement, T>("SelectorClass2", row, column, obj => { obj.SetValue(SelectorClassSetting.SelectorClass2Property, selectorClassName); });
        }

        /// <summary>
        /// Set a 3rd Selector Class at X-Y (row, column)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="selectorClassName"></param>
        /// <returns></returns>
        private static SettingsChain<T> SetSelectorClass3<T>(this SettingsChain<T> chain, int row, int column, string selectorClassName)
            where T : FrameworkElement
        {
            return chain.SetAttachedProperty<FrameworkElement, T>("SelectorClass3", row, column, obj => { obj.SetValue(SelectorClassSetting.SelectorClass3Property, selectorClassName); });
        }

        public enum SelectorPosition
        {
            One = 1,
            Two = 2,
            Three = 3
        }

        /// <summary>
        /// Update Selector Class in Selector Position (1, 2, or 3) at X-Y (row, column)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="selectorClassName"></param>
        /// <returns></returns>
        public static T UpdateSelectorClass<T>(this T chain, string key, int row, int column, SelectorPosition position, string newSelectorClassName)
            where T : FrameworkElement
        {
            switch ((int)position)
            {
                case 1:
                    chain.GetChildFromParent<FrameworkElement, T>(key, row, column).SetValue(SelectorClassSetting.SelectorClass1Property, newSelectorClassName);
                    break;
                case 2:
                    chain.GetChildFromParent<FrameworkElement, T>(key, row, column).SetValue(SelectorClassSetting.SelectorClass2Property, newSelectorClassName);
                    break;
                case 3:
                    chain.GetChildFromParent<FrameworkElement, T>(key, row, column).SetValue(SelectorClassSetting.SelectorClass3Property, newSelectorClassName);
                    break;
                default:
                    break;
            }

            return chain;
        }

        /// <summary>
        /// Update Selector Class in Selector Position (1, 2, or 3) at X-Y (row, column) where Border is a Composite
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="chain"></param>
        /// <param name="key"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="position"></param>
        /// <param name="newSelectorClassName"></param>
        /// <returns></returns>
        public static Border UpdateSelectorClass<T>(this Border chain, int row, int column, SelectorPosition position, string newSelectorClassName)
            where T : FrameworkElement
        {
            chain.GetParentFromComposite<T>().UpdateSelectorClass<T>(chain.GetKey(), 0, 0, position, newSelectorClassName);
            return chain;
        }
        
        /// <summary>
        /// Update Selector Class in Selector Position (1, 2, or 3) at X-Y (row, column) on Child (FrameworkElement)
        /// </summary>
        /// <param name="fe"></param>
        /// <param name="position"></param>
        /// <param name="newSelectorClassName"></param>
        /// <returns></returns>
        public static FrameworkElement UpdateSelectorClass(this FrameworkElement fe, SelectorPosition position, string newSelectorClassName)
        {
            switch ((int)position)
            {
                case 1:
                    fe.SetValue(SelectorClassSetting.SelectorClass1Property, newSelectorClassName);
                    break;
                case 2:
                    fe.SetValue(SelectorClassSetting.SelectorClass2Property, newSelectorClassName);
                    break;
                case 3:
                    fe.SetValue(SelectorClassSetting.SelectorClass3Property, newSelectorClassName);
                    break;
                default:
                    break;
            }

            return fe;
        }
    }//end of class

    public static class SelectorClassSetting
    {
        //Class 1
        public static string GetSelectorClass1(DependencyObject obj)
        {
            return (string)obj.GetValue(SelectorClass1Property);
        }

        public static void SetSelectorClass1(DependencyObject obj, string value)
        {
            obj.SetValue(SelectorClass1Property, value);
        }

        public static readonly DependencyProperty SelectorClass1Property =
            DependencyProperty.RegisterAttached(
                "SelectorClass1",
                typeof(string),
                typeof(SelectorClassSetting),
                new FrameworkPropertyMetadata(String.Empty));

        //Class 2
        public static string GetSelectorClass2(DependencyObject obj)
        {
            return (string)obj.GetValue(SelectorClass2Property);
        }

        public static void SetSelectorClass2(DependencyObject obj, string value)
        {
            obj.SetValue(SelectorClass2Property, value);
        }

        public static readonly DependencyProperty SelectorClass2Property =
            DependencyProperty.RegisterAttached(
                "SelectorClass2",
                typeof(string),
                typeof(SelectorClassSetting),
                new FrameworkPropertyMetadata(String.Empty));

        //Class 3
        public static string GetSelectorClass3(DependencyObject obj)
        {
            return (string)obj.GetValue(SelectorClass3Property);
        }

        public static void SetSelectorClass3(DependencyObject obj, string value)
        {
            obj.SetValue(SelectorClass3Property, value);
        }

        public static readonly DependencyProperty SelectorClass3Property =
            DependencyProperty.RegisterAttached(
                "SelectorClass3",
                typeof(string),
                typeof(SelectorClassSetting),
                new FrameworkPropertyMetadata(String.Empty));
    }
}//end of namespace
